diff options
author | Ian Lance Taylor <iant@golang.org> | 2022-02-11 14:53:56 -0800 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2022-02-11 15:01:19 -0800 |
commit | 8dc2499aa62f768c6395c9754b8cabc1ce25c494 (patch) | |
tree | 43d7fd2bbfd7ad8c9625a718a5e8718889351994 /libgo/go/syscall | |
parent | 9a56779dbc4e2d9c15be8d31e36f2f59be7331a8 (diff) | |
download | gcc-8dc2499aa62f768c6395c9754b8cabc1ce25c494.zip gcc-8dc2499aa62f768c6395c9754b8cabc1ce25c494.tar.gz gcc-8dc2499aa62f768c6395c9754b8cabc1ce25c494.tar.bz2 |
libgo: update to Go1.18beta2
gotools/
* Makefile.am (go_cmd_cgo_files): Add ast_go118.go
(check-go-tool): Copy golang.org/x/tools directories.
* Makefile.in: Regenerate.
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/384695
Diffstat (limited to 'libgo/go/syscall')
51 files changed, 728 insertions, 336 deletions
diff --git a/libgo/go/syscall/asan0.go b/libgo/go/syscall/asan0.go new file mode 100644 index 0000000..08bc44d --- /dev/null +++ b/libgo/go/syscall/asan0.go @@ -0,0 +1,19 @@ +// Copyright 2021 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 !asan + +package syscall + +import ( + "unsafe" +) + +const asanenabled = false + +func asanRead(addr unsafe.Pointer, len int) { +} + +func asanWrite(addr unsafe.Pointer, len int) { +} diff --git a/libgo/go/syscall/bpf_bsd.go b/libgo/go/syscall/bpf_bsd.go index 452d4cf..735c078 100644 --- a/libgo/go/syscall/bpf_bsd.go +++ b/libgo/go/syscall/bpf_bsd.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build dragonfly || freebsd || netbsd || openbsd -// +build dragonfly freebsd netbsd openbsd // Berkeley packet filter for BSD variants diff --git a/libgo/go/syscall/creds_test.go b/libgo/go/syscall/creds_test.go index c1a8b51..1ee56fc 100644 --- a/libgo/go/syscall/creds_test.go +++ b/libgo/go/syscall/creds_test.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build linux -// +build linux package syscall_test diff --git a/libgo/go/syscall/dirent.go b/libgo/go/syscall/dirent.go index 1e95946..504b9fb 100644 --- a/libgo/go/syscall/dirent.go +++ b/libgo/go/syscall/dirent.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris -// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris package syscall diff --git a/libgo/go/syscall/dirent_test.go b/libgo/go/syscall/dirent_test.go index 71b445b..aeb40e5 100644 --- a/libgo/go/syscall/dirent_test.go +++ b/libgo/go/syscall/dirent_test.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris -// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package syscall_test @@ -23,7 +22,7 @@ import ( func TestDirent(t *testing.T) { const ( - direntBufSize = 2048 + direntBufSize = 2048 // arbitrary? See https://go.dev/issue/37323. filenameMinSize = 11 ) @@ -38,23 +37,38 @@ func TestDirent(t *testing.T) { } } - buf := bytes.Repeat([]byte("DEADBEAF"), direntBufSize/8) + names := make([]string, 0, 10) + fd, err := syscall.Open(d, syscall.O_RDONLY, 0) if err != nil { t.Fatalf("syscall.open: %v", err) } defer syscall.Close(fd) - n, err := syscall.ReadDirent(fd, buf) - if err != nil { - t.Fatalf("syscall.readdir: %v", err) - } - buf = buf[:n] - names := make([]string, 0, 10) - for len(buf) > 0 { - var bc int - bc, _, names = syscall.ParseDirent(buf, -1, names) - buf = buf[bc:] + buf := bytes.Repeat([]byte{0xCD}, direntBufSize) + for { + n, err := syscall.ReadDirent(fd, buf) + if err == syscall.EINVAL { + // On linux, 'man getdents64' says that EINVAL indicates “result buffer is too small”. + // Try a bigger buffer. + t.Logf("ReadDirent: %v; retrying with larger buffer", err) + buf = bytes.Repeat([]byte{0xCD}, len(buf)*2) + continue + } + if err != nil { + t.Fatalf("syscall.readdir: %v", err) + } + t.Logf("ReadDirent: read %d bytes", n) + if n == 0 { + break + } + + var consumed, count int + consumed, count, names = syscall.ParseDirent(buf[:n], -1, names) + t.Logf("ParseDirent: %d new name(s)", count) + if consumed != n { + t.Fatalf("ParseDirent: consumed %d bytes; expected %d", consumed, n) + } } sort.Strings(names) diff --git a/libgo/go/syscall/endian_big.go b/libgo/go/syscall/endian_big.go index a38e9c6..e6b1163 100644 --- a/libgo/go/syscall/endian_big.go +++ b/libgo/go/syscall/endian_big.go @@ -1,9 +1,8 @@ // Copyright 2016 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 ppc64 || s390x || mips || mips64 || armbe || arm64be || m68k || ppc || mips64p32 || s390 || shbe || sparc || sparc64 -// +build ppc64 s390x mips mips64 armbe arm64be m68k ppc mips64p32 s390 shbe sparc sparc64 package syscall diff --git a/libgo/go/syscall/endian_little.go b/libgo/go/syscall/endian_little.go index 2332fa3..63e46d8 100644 --- a/libgo/go/syscall/endian_little.go +++ b/libgo/go/syscall/endian_little.go @@ -1,9 +1,8 @@ // Copyright 2016 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 386 || alpha || amd64 || amd64p32 || arm || arm64 || ia64 || ppc64le || mips64le || mipsle || mips64p32le || nios2 || riscv || riscv64 || sh || wasm -// +build 386 alpha amd64 amd64p32 arm arm64 ia64 ppc64le mips64le mipsle mips64p32le nios2 riscv riscv64 sh wasm package syscall diff --git a/libgo/go/syscall/env_unix.go b/libgo/go/syscall/env_unix.go index 0d95c55..8d82d58 100644 --- a/libgo/go/syscall/env_unix.go +++ b/libgo/go/syscall/env_unix.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || plan9 -// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris plan9 // Unix environment variables. diff --git a/libgo/go/syscall/exec_bsd.go b/libgo/go/syscall/exec_bsd.go index ad65f63..c05ae13 100644 --- a/libgo/go/syscall/exec_bsd.go +++ b/libgo/go/syscall/exec_bsd.go @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build aix || darwin || dragonfly || freebsd || hurd || netbsd || openbsd || solaris -// +build aix darwin dragonfly freebsd hurd netbsd openbsd solaris +//go:build aix || darwin || dragonfly || hurd || netbsd || openbsd || solaris package syscall import ( + "runtime" "unsafe" ) @@ -152,12 +152,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr groups = &gids[0] } if !cred.NoSetGroups { - err2 := setgroups(ngroups, groups) - if err2 == nil { - err1 = 0 - } else { - err1 = err2.(Errno) - } + err1 = raw_setgroups(ngroups, groups) if err1 != 0 { goto childerror } @@ -185,11 +180,19 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr // Pass 1: look for fd[i] < i and move those up above len(fd) // so that pass 2 won't stomp on an fd it needs later. if pipe < nextfd { - err1 = raw_dup2(pipe, nextfd) - if err1 != 0 { - goto childerror + switch runtime.GOOS { + case "netbsd": + err1 = raw_dup3(pipe, nextfd, O_CLOEXEC) + if err1 != 0 { + goto childerror + } + default: + err1 = raw_dup2(pipe, nextfd) + if err1 != 0 { + goto childerror + } + raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC) } - raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC) pipe = nextfd nextfd++ } @@ -198,11 +201,19 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr if nextfd == pipe { // don't stomp on pipe nextfd++ } - err1 = raw_dup2(fd[i], nextfd) - if err1 != 0 { - goto childerror + switch runtime.GOOS { + case "netbsd": + err1 = raw_dup3(fd[i], nextfd, O_CLOEXEC) + if err1 != 0 { + goto childerror + } + default: + err1 = raw_dup2(fd[i], nextfd) + if err1 != 0 { + goto childerror + } + raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC) } - raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC) fd[i] = nextfd nextfd++ } diff --git a/libgo/go/syscall/exec_freebsd.go b/libgo/go/syscall/exec_freebsd.go new file mode 100644 index 0000000..f02f89d --- /dev/null +++ b/libgo/go/syscall/exec_freebsd.go @@ -0,0 +1,294 @@ +// Copyright 2021 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. + +package syscall + +import ( + "runtime" + "unsafe" +) + +//sysnb raw_procctl(idtype int, id int64, cmd int, data unsafe.Pointer) (ret int, err Errno) +//procctl(idtype _C_int, id int64, cmd int, data unsafe.Pointer) _C_int + +type SysProcAttr struct { + Chroot string // Chroot. + Credential *Credential // Credential. + Ptrace bool // Enable tracing. + Setsid bool // Create session. + // Setpgid sets the process group ID of the child to Pgid, + // or, if Pgid == 0, to the new child's process ID. + Setpgid bool + // Setctty sets the controlling terminal of the child to + // file descriptor Ctty. Ctty must be a descriptor number + // in the child process: an index into ProcAttr.Files. + // This is only meaningful if Setsid is true. + Setctty bool + Noctty bool // Detach fd 0 from controlling terminal + Ctty int // Controlling TTY fd + // Foreground places the child process group in the foreground. + // This implies Setpgid. The Ctty field must be set to + // the descriptor of the controlling TTY. + // Unlike Setctty, in this case Ctty must be a descriptor + // number in the parent process. + Foreground bool + Pgid int // Child's process group ID if Setpgid. + Pdeathsig Signal // Signal that the process will get when its parent dies (Linux and FreeBSD only) +} + +const ( + _P_PID = 0 + + _PROC_PDEATHSIG_CTL = 11 +) + +// Implemented in runtime package. +func runtime_BeforeFork() +func runtime_AfterFork() +func runtime_AfterForkInChild() + +// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child. +// If a dup or exec fails, write the errno error to pipe. +// (Pipe is close-on-exec so if exec succeeds, it will be closed.) +// In the child, this function must not acquire any locks, because +// they might have been locked at the time of the fork. This means +// no rescheduling, no malloc calls, and no new stack segments. +// For the same reason compiler does not race instrument it. +// The calls to RawSyscall are okay because they are assembly +// functions that do not grow the stack. +//go:norace +func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) { + // Declare all variables at top in case any + // declarations require heap allocation (e.g., err1). + var ( + r1 Pid_t + err1 Errno + nextfd int + i int + ) + + // Record parent PID so child can test if it has died. + ppid := raw_getpid() + + // guard against side effects of shuffling fds below. + // Make sure that nextfd is beyond any currently open files so + // that we can't run the risk of overwriting any of them. + fd := make([]int, len(attr.Files)) + nextfd = len(attr.Files) + for i, ufd := range attr.Files { + if nextfd < int(ufd) { + nextfd = int(ufd) + } + fd[i] = int(ufd) + } + nextfd++ + + // About to call fork. + // No more allocation or calls of non-assembly functions. + runtime_BeforeFork() + r1, err1 = raw_fork() + if err1 != 0 { + runtime_AfterFork() + return 0, err1 + } + + if r1 != 0 { + // parent; return PID + runtime_AfterFork() + return int(r1), 0 + } + + // Fork succeeded, now in child. + + // Enable tracing if requested. + if sys.Ptrace { + err1 = raw_ptrace(_PTRACE_TRACEME, 0, 0, 0) + if err1 != 0 { + goto childerror + } + } + + // Session ID + if sys.Setsid { + err1 = raw_setsid() + if err1 != 0 { + goto childerror + } + } + + // Set process group + if sys.Setpgid || sys.Foreground { + // Place child in process group. + err1 = raw_setpgid(0, sys.Pgid) + if err1 != 0 { + goto childerror + } + } + + if sys.Foreground { + pgrp := Pid_t(sys.Pgid) + if pgrp == 0 { + pgrp = raw_getpid() + } + + // Place process group in foreground. + err1 = raw_ioctl(sys.Ctty, TIOCSPGRP, unsafe.Pointner(&pgrp)) + if err1 != 0 { + goto childerror + } + } + + // Restore the signal mask. We do this after TIOCSPGRP to avoid + // having the kernel send a SIGTTOU signal to the process group. + runtime_AfterForkInChild() + + // Chroot + if chroot != nil { + err1 = raw_chroot(chroot) + if err1 != 0 { + goto childerror + } + } + + // User and groups + if cred := sys.Credential; cred != nil { + ngroups := len(cred.Groups) + var groups *Gid_t + if ngroups > 0 { + gids := make([]Gid_t, ngroups) + for i, v := range cred.Groups { + gids[i] = Gid_t(v) + } + groups = &gids[0] + } + + if !cred.NoSetGroups { + err1 = raw_setgroups(ngroups, groups) + if err1 != 0 { + goto childerror + } + } + err2 := Setgid(int(cred.Gid)) + if err2 != nil { + err1 = err2.(Errno) + goto childerror + } + err2 = Setuid(int(cred.Uid)) + if err2 != nil { + err1 = err2.(Errno) + goto childerror + } + + } + + // Chdir + if dir != nil { + err1 = raw_chdir(dir) + if err1 != 0 { + goto childerror + } + } + + // Parent death signal + if sys.Pdeathsig != 0 { + _, err1 = raw_procctl(_P_PID, 0, _PROC_PDEATHSIG_CTL, unsafe.Pointer(&sys.Pdeathsig)) + + if err1 != 0 { + goto childerror + } + + // Signal self if parent is already dead. This might cause a + // duplicate signal in rare cases, but it won't matter when + // using SIGKILL. + r1 = raw_getppid() + if r1 != ppid { + pid := raw_getpid() + err1 = raw_kill(pid, sys.Pdeathsig) + if err1 != 0 { + goto childerror + } + } + } + + // Pass 1: look for fd[i] < i and move those up above len(fd) + // so that pass 2 won't stomp on an fd it needs later. + if pipe < nextfd { + _, err1 = raw_fcntl(pipe, _F_DUP2FD_CLOEXEC, nextfd) + if err1 != 0 { + goto childerror + } + pipe = nextfd + nextfd++ + } + for i = 0; i < len(fd); i++ { + if fd[i] >= 0 && fd[i] < int(i) { + if nextfd == pipe { // don't stomp on pipe + nextfd++ + } + err1 = raw_fcntl(fd[i], _F_DUP2FD_CLOEXEC, nextfd) + if err1 != 0 { + goto childerror + } + fd[i] = nextfd + nextfd++ + } + } + + // Pass 2: dup fd[i] down onto i. + for i = 0; i < len(fd); i++ { + if fd[i] == -1 { + raw_close(i) + continue + } + if fd[i] == int(i) { + // dup2(i, i) won't clear close-on-exec flag on Linux, + // probably not elsewhere either. + _, err1 = raw_fcntl(fd[i], _F_SETFD, 0) + if err1 != 0 { + goto childerror + } + continue + } + // The new fd is created NOT close-on-exec, + // which is exactly what we want. + err1 = raw_dup2(fd[i], i) + if err1 != 0 { + goto childerror + } + } + + // By convention, we don't close-on-exec the fds we are + // started with, so if len(fd) < 3, close 0, 1, 2 as needed. + // Programs that know they inherit fds >= 3 will need + // to set them close-on-exec. + for i = len(fd); i < 3; i++ { + raw_close(i) + } + + // Detach fd 0 from tty + if sys.Noctty { + _, err = raw_ioctl(0, TIOCNOTTY, 0) + if err1 != 0 { + goto childerror + } + } + + // Set the controlling TTY to Ctty + if sys.Setctty { + _, err1 = raw_ioctl(sys.Cty, TIOCSCTTY, 0) + if err1 != 0 { + goto childerror + } + } + + // Time to exec. + err1 = raw_execve(argv0, &argv[0], &envv[0]) + +childerror: + // send error code on pipe + raw_write(pipe, (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1))) + for { + raw_exit(253) + } +} diff --git a/libgo/go/syscall/exec_linux.go b/libgo/go/syscall/exec_linux.go index c9be86b..86fb8e8 100644 --- a/libgo/go/syscall/exec_linux.go +++ b/libgo/go/syscall/exec_linux.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build linux -// +build linux package syscall @@ -57,7 +56,7 @@ type SysProcAttr struct { // number in the parent process. Foreground bool Pgid int // Child's process group ID if Setpgid. - Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only) + Pdeathsig Signal // Signal that the process will get when its parent dies (Linux and FreeBSD only) Cloneflags uintptr // Flags for clone calls (Linux only) Unshareflags uintptr // Flags for unshare calls (Linux only) UidMappings []SysProcIDMap // User ID mappings for user namespaces. @@ -459,13 +458,7 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att // so that pass 2 won't stomp on an fd it needs later. if pipe < nextfd { err1 = raw_dup3(pipe, nextfd, O_CLOEXEC) - if err1 == ENOSYS { - err1 = raw_dup2(pipe, nextfd) - if err1 != 0 { - goto childerror - } - raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC) - } else if err1 != 0 { + if err1 != 0 { goto childerror } pipe = nextfd @@ -477,13 +470,7 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att nextfd++ } err1 = raw_dup3(fd[i], nextfd, O_CLOEXEC) - if err1 == ENOSYS { - err1 = raw_dup2(fd[i], nextfd) - if err1 != 0 { - goto childerror - } - raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC) - } else if err1 != 0 { + if err1 != 0 { goto childerror } fd[i] = nextfd @@ -508,7 +495,7 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att } // The new fd is created NOT close-on-exec, // which is exactly what we want. - err1 = raw_dup2(fd[i], i) + err1 = raw_dup3(fd[i], i, 0) if err1 != 0 { goto childerror } @@ -561,19 +548,7 @@ childerror: // Try to open a pipe with O_CLOEXEC set on both file descriptors. func forkExecPipe(p []int) (err error) { - err = Pipe2(p, O_CLOEXEC) - // pipe2 was added in 2.6.27 and our minimum requirement is 2.6.23, so it - // might not be implemented. - if err == ENOSYS { - if err = Pipe(p); err != nil { - return - } - if _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != nil { - return - } - _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC) - } - return + return Pipe2(p, O_CLOEXEC) } func formatIDMappings(idMap []SysProcIDMap) []byte { diff --git a/libgo/go/syscall/exec_linux_test.go b/libgo/go/syscall/exec_linux_test.go index ec0a4c0..abe6fdb 100644 --- a/libgo/go/syscall/exec_linux_test.go +++ b/libgo/go/syscall/exec_linux_test.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build linux -// +build linux package syscall_test @@ -111,14 +110,6 @@ func checkUserNS(t *testing.T) { t.Skip("kernel doesn't support user namespaces") } } - - // When running under the Go continuous build, skip tests for - // now when under Kubernetes. (where things are root but not quite) - // Both of these are our own environment variables. - // See Issue 12815. - if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" { - t.Skip("skipping test on Kubernetes-based builders; see Issue 12815") - } } func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd { @@ -201,14 +192,6 @@ func TestUnshare(t *testing.T) { t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace") } - // When running under the Go continuous build, skip tests for - // now when under Kubernetes. (where things are root but not quite) - // Both of these are our own environment variables. - // See Issue 12815. - if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" { - t.Skip("skipping test on Kubernetes-based builders; see Issue 12815") - } - path := "/proc/net/dev" if _, err := os.Stat(path); err != nil { if os.IsNotExist(err) { @@ -526,9 +509,7 @@ func mustSupportAmbientCaps(t *testing.T) { buf[i] = byte(b) } ver := string(buf[:]) - if i := strings.Index(ver, "\x00"); i != -1 { - ver = ver[:i] - } + ver, _, _ = strings.Cut(ver, "\x00") if strings.HasPrefix(ver, "2.") || strings.HasPrefix(ver, "3.") || strings.HasPrefix(ver, "4.1.") || diff --git a/libgo/go/syscall/exec_pdeathsig_test.go b/libgo/go/syscall/exec_pdeathsig_test.go new file mode 100644 index 0000000..96ae27b --- /dev/null +++ b/libgo/go/syscall/exec_pdeathsig_test.go @@ -0,0 +1,134 @@ +// Copyright 2015 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 freebsd || linux + +package syscall_test + +import ( + "bufio" + "fmt" + "io" + "os" + "os/exec" + "os/signal" + "path/filepath" + "syscall" + "testing" + "time" +) + +func TestDeathSignal(t *testing.T) { + if os.Getuid() != 0 { + t.Skip("skipping root only test") + } + + // Copy the test binary to a location that a non-root user can read/execute + // after we drop privileges + tempDir, err := os.MkdirTemp("", "TestDeathSignal") + if err != nil { + t.Fatalf("cannot create temporary directory: %v", err) + } + defer os.RemoveAll(tempDir) + os.Chmod(tempDir, 0755) + + tmpBinary := filepath.Join(tempDir, filepath.Base(os.Args[0])) + + src, err := os.Open(os.Args[0]) + if err != nil { + t.Fatalf("cannot open binary %q, %v", os.Args[0], err) + } + defer src.Close() + + dst, err := os.OpenFile(tmpBinary, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755) + if err != nil { + t.Fatalf("cannot create temporary binary %q, %v", tmpBinary, err) + } + if _, err := io.Copy(dst, src); err != nil { + t.Fatalf("failed to copy test binary to %q, %v", tmpBinary, err) + } + err = dst.Close() + if err != nil { + t.Fatalf("failed to close test binary %q, %v", tmpBinary, err) + } + + cmd := exec.Command(tmpBinary) + cmd.Env = append(os.Environ(), "GO_DEATHSIG_PARENT=1") + chldStdin, err := cmd.StdinPipe() + if err != nil { + t.Fatalf("failed to create new stdin pipe: %v", err) + } + chldStdout, err := cmd.StdoutPipe() + if err != nil { + t.Fatalf("failed to create new stdout pipe: %v", err) + } + cmd.Stderr = os.Stderr + + err = cmd.Start() + defer cmd.Wait() + if err != nil { + t.Fatalf("failed to start first child process: %v", err) + } + + chldPipe := bufio.NewReader(chldStdout) + + if got, err := chldPipe.ReadString('\n'); got == "start\n" { + syscall.Kill(cmd.Process.Pid, syscall.SIGTERM) + + go func() { + time.Sleep(5 * time.Second) + chldStdin.Close() + }() + + want := "ok\n" + if got, err = chldPipe.ReadString('\n'); got != want { + t.Fatalf("expected %q, received %q, %v", want, got, err) + } + } else { + t.Fatalf("did not receive start from child, received %q, %v", got, err) + } +} + +func deathSignalParent() { + cmd := exec.Command(os.Args[0]) + cmd.Env = append(os.Environ(), + "GO_DEATHSIG_PARENT=", + "GO_DEATHSIG_CHILD=1", + ) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + attrs := syscall.SysProcAttr{ + Pdeathsig: syscall.SIGUSR1, + // UID/GID 99 is the user/group "nobody" on RHEL/Fedora and is + // unused on Ubuntu + Credential: &syscall.Credential{Uid: 99, Gid: 99}, + } + cmd.SysProcAttr = &attrs + + err := cmd.Start() + if err != nil { + fmt.Fprintf(os.Stderr, "death signal parent error: %v\n", err) + os.Exit(1) + } + cmd.Wait() + os.Exit(0) +} + +func deathSignalChild() { + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGUSR1) + go func() { + <-c + fmt.Println("ok") + os.Exit(0) + }() + fmt.Println("start") + + buf := make([]byte, 32) + os.Stdin.Read(buf) + + // We expected to be signaled before stdin closed + fmt.Println("not ok") + os.Exit(1) +} diff --git a/libgo/go/syscall/exec_unix.go b/libgo/go/syscall/exec_unix.go index 7e01648..c99171b 100644 --- a/libgo/go/syscall/exec_unix.go +++ b/libgo/go/syscall/exec_unix.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris -// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris // Fork, exec, wait, etc. @@ -210,9 +209,6 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) sys = &zeroSysProcAttr } - p[0] = -1 - p[1] = -1 - // Convert args to C form. argv0p, err := BytePtrFromString(argv0) if err != nil { @@ -262,14 +258,17 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) // Allocate child status pipe close on exec. if err = forkExecPipe(p[:]); err != nil { - goto error + ForkLock.Unlock() + return 0, err } // Kick off child. pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1]) if err1 != 0 { - err = Errno(err1) - goto error + Close(p[0]) + Close(p[1]) + ForkLock.Unlock() + return 0, Errno(err1) } ForkLock.Unlock() @@ -301,14 +300,6 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) // Read got EOF, so pipe closed on exec, so exec succeeded. return pid, nil - -error: - if p[0] >= 0 { - Close(p[0]) - Close(p[1]) - } - ForkLock.Unlock() - return 0, err } // Combination of fork and exec, careful to be thread safe. diff --git a/libgo/go/syscall/exec_unix_test.go b/libgo/go/syscall/exec_unix_test.go index 3b78d20..29fd760 100644 --- a/libgo/go/syscall/exec_unix_test.go +++ b/libgo/go/syscall/exec_unix_test.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris -// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris package syscall_test @@ -329,7 +328,6 @@ func TestExecHelper(t *testing.T) { // We don't have to worry about restoring these values. // We are in a child process that only runs this test, // and we are going to call syscall.Exec anyhow. - runtime.GOMAXPROCS(50) os.Setenv("GO_WANT_HELPER_PROCESS", "3") stop := time.Now().Add(time.Second) diff --git a/libgo/go/syscall/exec_windows.go b/libgo/go/syscall/exec_windows.go index 18d1502..9d10d6a 100644 --- a/libgo/go/syscall/exec_windows.go +++ b/libgo/go/syscall/exec_windows.go @@ -390,8 +390,10 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle } fd = fd[:j] + willInheritHandles := len(fd) > 0 && !sys.NoInheritHandles + // Do not accidentally inherit more than these handles. - if len(fd) > 0 { + if willInheritHandles { err = updateProcThreadAttribute(si.ProcThreadAttributeList, 0, _PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&fd[0]), uintptr(len(fd))*unsafe.Sizeof(fd[0]), nil, nil) if err != nil { return 0, 0, err @@ -401,9 +403,9 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle pi := new(ProcessInformation) flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT | _EXTENDED_STARTUPINFO_PRESENT if sys.Token != 0 { - err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, len(fd) > 0 && !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi) + err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi) } else { - err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, len(fd) > 0 && !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi) + err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi) } if err != nil { return 0, 0, err diff --git a/libgo/go/syscall/export_unix_test.go b/libgo/go/syscall/export_unix_test.go index f32118b5..184eb84 100644 --- a/libgo/go/syscall/export_unix_test.go +++ b/libgo/go/syscall/export_unix_test.go @@ -2,8 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris -// +build dragonfly freebsd hurd linux netbsd openbsd solaris +//go:build dragonfly || freebsd || hurd || linux || netbsd || openbsd package syscall diff --git a/libgo/go/syscall/forkpipe.go b/libgo/go/syscall/forkpipe.go index 79cbdf4..6f7d29c 100644 --- a/libgo/go/syscall/forkpipe.go +++ b/libgo/go/syscall/forkpipe.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build aix || darwin || solaris -// +build aix darwin solaris package syscall diff --git a/libgo/go/syscall/forkpipe2.go b/libgo/go/syscall/forkpipe2.go index bdffdcd..01c8048 100644 --- a/libgo/go/syscall/forkpipe2.go +++ b/libgo/go/syscall/forkpipe2.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build dragonfly || freebsd || hurd || netbsd || openbsd -// +build dragonfly freebsd hurd netbsd openbsd package syscall diff --git a/libgo/go/syscall/fs_js.go b/libgo/go/syscall/fs_js.go index 0170516..3541446 100644 --- a/libgo/go/syscall/fs_js.go +++ b/libgo/go/syscall/fs_js.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build js && wasm -// +build js,wasm package syscall @@ -492,14 +491,14 @@ func Pipe(fd []int) error { return ENOSYS } -func fsCall(name string, args ...interface{}) (js.Value, error) { +func fsCall(name string, args ...any) (js.Value, error) { type callResult struct { val js.Value err error } c := make(chan callResult, 1) - f := js.FuncOf(func(this js.Value, args []js.Value) interface{} { + f := js.FuncOf(func(this js.Value, args []js.Value) any { var res callResult if len(args) >= 1 { // on Node.js 8, fs.utimes calls the callback without any arguments diff --git a/libgo/go/syscall/getdirentries_test.go b/libgo/go/syscall/getdirentries_test.go index 814e656..ddd8208 100644 --- a/libgo/go/syscall/getdirentries_test.go +++ b/libgo/go/syscall/getdirentries_test.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build darwin || freebsd || netbsd || openbsd -// +build darwin freebsd netbsd openbsd package syscall_test diff --git a/libgo/go/syscall/js/export_test.go b/libgo/go/syscall/js/export_test.go index 1b5ed3c..fb61dae 100644 --- a/libgo/go/syscall/js/export_test.go +++ b/libgo/go/syscall/js/export_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build js,wasm +//go:build js && wasm package js diff --git a/libgo/go/syscall/js/func.go b/libgo/go/syscall/js/func.go index da4cf68..cc94972 100644 --- a/libgo/go/syscall/js/func.go +++ b/libgo/go/syscall/js/func.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build js,wasm +//go:build js && wasm package js @@ -10,12 +10,10 @@ import "sync" var ( funcsMu sync.Mutex - funcs = make(map[uint32]func(Value, []Value) interface{}) + funcs = make(map[uint32]func(Value, []Value) any) nextFuncID uint32 = 1 ) -var _ Wrapper = Func{} // Func must implement Wrapper - // Func is a wrapped Go function to be called by JavaScript. type Func struct { Value // the JavaScript function that invokes the Go function @@ -40,7 +38,7 @@ type Func struct { // new goroutine. // // Func.Release must be called to free up resources when the function will not be invoked any more. -func FuncOf(fn func(this Value, args []Value) interface{}) Func { +func FuncOf(fn func(this Value, args []Value) any) Func { funcsMu.Lock() id := nextFuncID nextFuncID++ diff --git a/libgo/go/syscall/js/js.go b/libgo/go/syscall/js/js.go index a48bbd4..a5210fa 100644 --- a/libgo/go/syscall/js/js.go +++ b/libgo/go/syscall/js/js.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build js,wasm +//go:build js && wasm // Package js gives access to the WebAssembly host environment when using the js/wasm architecture. // Its API is based on JavaScript semantics. @@ -27,12 +27,6 @@ type ref uint64 // nanHead are the upper 32 bits of a ref which are set if the value is not encoded as an IEEE 754 number (see above). const nanHead = 0x7FF80000 -// Wrapper is implemented by types that are backed by a JavaScript value. -type Wrapper interface { - // JSValue returns a JavaScript value associated with an object. - JSValue() Value -} - // Value represents a JavaScript value. The zero value is the JavaScript value "undefined". // Values can be checked for equality with the Equal method. type Value struct { @@ -50,11 +44,6 @@ const ( typeFlagFunction ) -// JSValue implements Wrapper interface. -func (v Value) JSValue() Value { - return v -} - func makeValue(r ref) Value { var gcPtr *ref typeFlag := (r >> 32) & 7 @@ -159,12 +148,12 @@ func Global() Value { // | map[string]interface{} | new object | // // Panics if x is not one of the expected types. -func ValueOf(x interface{}) Value { +func ValueOf(x any) Value { switch x := x.(type) { - case Value: // should precede Wrapper to avoid a loop + case Value: return x - case Wrapper: - return x.JSValue() + case Func: + return x.Value case nil: return valueNull case bool: @@ -203,13 +192,13 @@ func ValueOf(x interface{}) Value { return floatValue(x) case string: return makeValue(stringVal(x)) - case []interface{}: + case []any: a := arrayConstructor.New(len(x)) for i, s := range x { a.SetIndex(i, s) } return a - case map[string]interface{}: + case map[string]any: o := objectConstructor.New() for k, v := range x { o.Set(k, v) @@ -307,7 +296,7 @@ func valueGet(v ref, p string) ref // Set sets the JavaScript property p of value v to ValueOf(x). // It panics if v is not a JavaScript object. -func (v Value) Set(p string, x interface{}) { +func (v Value) Set(p string, x any) { if vType := v.Type(); !vType.isObject() { panic(&ValueError{"Value.Set", vType}) } @@ -346,7 +335,7 @@ func valueIndex(v ref, i int) ref // SetIndex sets the JavaScript index i of value v to ValueOf(x). // It panics if v is not a JavaScript object. -func (v Value) SetIndex(i int, x interface{}) { +func (v Value) SetIndex(i int, x any) { if vType := v.Type(); !vType.isObject() { panic(&ValueError{"Value.SetIndex", vType}) } @@ -358,7 +347,7 @@ func (v Value) SetIndex(i int, x interface{}) { func valueSetIndex(v ref, i int, x ref) -func makeArgs(args []interface{}) ([]Value, []ref) { +func makeArgs(args []any) ([]Value, []ref) { argVals := make([]Value, len(args)) argRefs := make([]ref, len(args)) for i, arg := range args { @@ -385,7 +374,7 @@ func valueLength(v ref) int // Call does a JavaScript call to the method m of value v with the given arguments. // It panics if v has no method m. // The arguments get mapped to JavaScript values according to the ValueOf function. -func (v Value) Call(m string, args ...interface{}) Value { +func (v Value) Call(m string, args ...any) Value { argVals, argRefs := makeArgs(args) res, ok := valueCall(v.ref, m, argRefs) runtime.KeepAlive(v) @@ -407,7 +396,7 @@ func valueCall(v ref, m string, args []ref) (ref, bool) // Invoke does a JavaScript call of the value v with the given arguments. // It panics if v is not a JavaScript function. // The arguments get mapped to JavaScript values according to the ValueOf function. -func (v Value) Invoke(args ...interface{}) Value { +func (v Value) Invoke(args ...any) Value { argVals, argRefs := makeArgs(args) res, ok := valueInvoke(v.ref, argRefs) runtime.KeepAlive(v) @@ -426,7 +415,7 @@ func valueInvoke(v ref, args []ref) (ref, bool) // New uses JavaScript's "new" operator with value v as constructor and the given arguments. // It panics if v is not a JavaScript function. // The arguments get mapped to JavaScript values according to the ValueOf function. -func (v Value) New(args ...interface{}) Value { +func (v Value) New(args ...any) Value { argVals, argRefs := makeArgs(args) res, ok := valueNew(v.ref, argRefs) runtime.KeepAlive(v) diff --git a/libgo/go/syscall/js/js_test.go b/libgo/go/syscall/js/js_test.go index 5fc9107..f860a5b 100644 --- a/libgo/go/syscall/js/js_test.go +++ b/libgo/go/syscall/js/js_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build js,wasm +//go:build js && wasm // To run these tests: // @@ -364,8 +364,8 @@ func TestType(t *testing.T) { } } -type object = map[string]interface{} -type array = []interface{} +type object = map[string]any +type array = []any func TestValueOf(t *testing.T) { a := js.ValueOf(array{0, array{0, 42, 0}, 0}) @@ -388,7 +388,7 @@ func TestZeroValue(t *testing.T) { func TestFuncOf(t *testing.T) { c := make(chan struct{}) - cb := js.FuncOf(func(this js.Value, args []js.Value) interface{} { + cb := js.FuncOf(func(this js.Value, args []js.Value) any { if got := args[0].Int(); got != 42 { t.Errorf("got %#v, want %#v", got, 42) } @@ -402,8 +402,8 @@ func TestFuncOf(t *testing.T) { func TestInvokeFunction(t *testing.T) { called := false - cb := js.FuncOf(func(this js.Value, args []js.Value) interface{} { - cb2 := js.FuncOf(func(this js.Value, args []js.Value) interface{} { + cb := js.FuncOf(func(this js.Value, args []js.Value) any { + cb2 := js.FuncOf(func(this js.Value, args []js.Value) any { called = true return 42 }) @@ -423,7 +423,7 @@ func TestInterleavedFunctions(t *testing.T) { c1 := make(chan struct{}) c2 := make(chan struct{}) - js.Global().Get("setTimeout").Invoke(js.FuncOf(func(this js.Value, args []js.Value) interface{} { + js.Global().Get("setTimeout").Invoke(js.FuncOf(func(this js.Value, args []js.Value) any { c1 <- struct{}{} <-c2 return nil @@ -432,7 +432,7 @@ func TestInterleavedFunctions(t *testing.T) { <-c1 c2 <- struct{}{} // this goroutine is running, but the callback of setTimeout did not return yet, invoke another function now - f := js.FuncOf(func(this js.Value, args []js.Value) interface{} { + f := js.FuncOf(func(this js.Value, args []js.Value) any { return nil }) f.Invoke() @@ -440,7 +440,7 @@ func TestInterleavedFunctions(t *testing.T) { func ExampleFuncOf() { var cb js.Func - cb = js.FuncOf(func(this js.Value, args []js.Value) interface{} { + cb = js.FuncOf(func(this js.Value, args []js.Value) any { fmt.Println("button clicked") cb.Release() // release the function if the button will not be clicked again return nil @@ -593,7 +593,7 @@ func BenchmarkDOM(b *testing.B) { } func TestGlobal(t *testing.T) { - ident := js.FuncOf(func(this js.Value, args []js.Value) interface{} { + ident := js.FuncOf(func(this js.Value, args []js.Value) any { return args[0] }) defer ident.Release() diff --git a/libgo/go/syscall/mkasm.go b/libgo/go/syscall/mkasm.go index e0ec466..dce61f3 100644 --- a/libgo/go/syscall/mkasm.go +++ b/libgo/go/syscall/mkasm.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build ignore -// +build ignore // mkasm.go generates assembly trampolines to call library routines from Go. // This program must be run after mksyscall.pl. diff --git a/libgo/go/syscall/mmap_unix_test.go b/libgo/go/syscall/mmap_unix_test.go index f4eb54d..e5f8ffc 100644 --- a/libgo/go/syscall/mmap_unix_test.go +++ b/libgo/go/syscall/mmap_unix_test.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd -// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd package syscall_test diff --git a/libgo/go/syscall/msan0.go b/libgo/go/syscall/msan0.go index 8509702..fba8a5f 100644 --- a/libgo/go/syscall/msan0.go +++ b/libgo/go/syscall/msan0.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build !msan -// +build !msan package syscall diff --git a/libgo/go/syscall/net_js.go b/libgo/go/syscall/net_js.go index ed46202..2ed4e19 100644 --- a/libgo/go/syscall/net_js.go +++ b/libgo/go/syscall/net_js.go @@ -6,7 +6,6 @@ // This file only exists to make the compiler happy. //go:build js && wasm -// +build js,wasm package syscall @@ -46,8 +45,7 @@ const ( SYS_FCNTL = 500 // unsupported ) -type Sockaddr interface { -} +type Sockaddr any type SockaddrInet4 struct { Port int diff --git a/libgo/go/syscall/netlink_linux.go b/libgo/go/syscall/netlink_linux.go index 0937ff7..2d81070 100644 --- a/libgo/go/syscall/netlink_linux.go +++ b/libgo/go/syscall/netlink_linux.go @@ -55,14 +55,22 @@ func NetlinkRIB(proto, family int) ([]byte, error) { return nil, err } defer Close(s) - lsa := &SockaddrNetlink{Family: AF_NETLINK} - if err := Bind(s, lsa); err != nil { + sa := &SockaddrNetlink{Family: AF_NETLINK} + if err := Bind(s, sa); err != nil { return nil, err } wb := newNetlinkRouteRequest(proto, 1, family) - if err := Sendto(s, wb, 0, lsa); err != nil { + if err := Sendto(s, wb, 0, sa); err != nil { return nil, err } + lsa, err := Getsockname(s) + if err != nil { + return nil, err + } + lsanl, ok := lsa.(*SockaddrNetlink) + if !ok { + return nil, EINVAL + } var tab []byte rbNew := make([]byte, Getpagesize()) done: @@ -82,16 +90,7 @@ done: return nil, err } for _, m := range msgs { - lsa, err := Getsockname(s) - if err != nil { - return nil, err - } - switch v := lsa.(type) { - case *SockaddrNetlink: - if m.Header.Seq != 1 || m.Header.Pid != v.Pid { - return nil, EINVAL - } - default: + if m.Header.Seq != 1 || m.Header.Pid != lsanl.Pid { return nil, EINVAL } if m.Header.Type == NLMSG_DONE { diff --git a/libgo/go/syscall/route_bsd.go b/libgo/go/syscall/route_bsd.go index 0dc5fc0..b9d19c5 100644 --- a/libgo/go/syscall/route_bsd.go +++ b/libgo/go/syscall/route_bsd.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build darwin || dragonfly || freebsd || netbsd || openbsd -// +build darwin dragonfly freebsd netbsd openbsd package syscall diff --git a/libgo/go/syscall/route_freebsd_32bit.go b/libgo/go/syscall/route_freebsd_32bit.go index 412833a..c70f0bb 100644 --- a/libgo/go/syscall/route_freebsd_32bit.go +++ b/libgo/go/syscall/route_freebsd_32bit.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build (freebsd && 386) || (freebsd && arm) -// +build freebsd,386 freebsd,arm package syscall diff --git a/libgo/go/syscall/route_freebsd_64bit.go b/libgo/go/syscall/route_freebsd_64bit.go index 5300bed..9febdfa 100644 --- a/libgo/go/syscall/route_freebsd_64bit.go +++ b/libgo/go/syscall/route_freebsd_64bit.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build (freebsd && amd64) || (freebsd && arm64) -// +build freebsd,amd64 freebsd,arm64 package syscall diff --git a/libgo/go/syscall/setuidgid_32_linux.go b/libgo/go/syscall/setuidgid_32_linux.go index 4e657c8..cb73fde 100644 --- a/libgo/go/syscall/setuidgid_32_linux.go +++ b/libgo/go/syscall/setuidgid_32_linux.go @@ -3,8 +3,6 @@ // license that can be found in the LICENSE file. //go:build linux && (386 || arm) -// +build linux -// +build 386 arm package syscall diff --git a/libgo/go/syscall/setuidgid_linux.go b/libgo/go/syscall/setuidgid_linux.go index c15090f..4e1804e 100644 --- a/libgo/go/syscall/setuidgid_linux.go +++ b/libgo/go/syscall/setuidgid_linux.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build linux && !386 && !arm -// +build linux,!386,!arm package syscall diff --git a/libgo/go/syscall/sockcmsg_unix.go b/libgo/go/syscall/sockcmsg_unix.go index aaeecdb..44ef9b8 100644 --- a/libgo/go/syscall/sockcmsg_unix.go +++ b/libgo/go/syscall/sockcmsg_unix.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris -// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris // Socket control messages diff --git a/libgo/go/syscall/sockcmsg_unix_other.go b/libgo/go/syscall/sockcmsg_unix_other.go index 0b75b18..6503dbd 100644 --- a/libgo/go/syscall/sockcmsg_unix_other.go +++ b/libgo/go/syscall/sockcmsg_unix_other.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build aix || darwin || freebsd || hurd || linux || netbsd || openbsd || solaris -// +build aix darwin freebsd hurd linux netbsd openbsd solaris package syscall diff --git a/libgo/go/syscall/socket.go b/libgo/go/syscall/socket.go index f42679d..54a4a99 100644 --- a/libgo/go/syscall/socket.go +++ b/libgo/go/syscall/socket.go @@ -12,6 +12,18 @@ package syscall import "unsafe" +// These functions are called from the internal/syscall/unix package. +// Use go:linkname to export them. +// +//go:linkname recvfromInet4 +//go:linkname recvfromInet6 +//go:linkname sendtoInet4 +//go:linkname sendtoInet6 +//go:linkname sendmsgNInet4 +//go:linkname sendmsgNInet6 +//go:linkname recvmsgInet4 +//go:linkname recvmsgInet6 + // For testing: clients can set this flag to force // creation of IPv6 sockets to return EAFNOSUPPORT. var SocketDisableIPv6 bool @@ -332,6 +344,119 @@ func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) { return } +func recvfromInet4(fd int, p []byte, flags int, from *SockaddrInet4) (n int, err error) { + var rsa RawSockaddrAny + var socklen Socklen_t = SizeofSockaddrAny + if n, err = recvfrom(fd, p, flags, &rsa, &socklen); err != nil { + return + } + pp := (*RawSockaddrInet4)(unsafe.Pointer(&rsa)) + port := (*[2]byte)(unsafe.Pointer(&pp.Port)) + from.Port = int(port[0])<<8 + int(port[1]) + from.Addr = pp.Addr + return +} + +func recvfromInet6(fd int, p []byte, flags int, from *SockaddrInet6) (n int, err error) { + var rsa RawSockaddrAny + var socklen Socklen_t = SizeofSockaddrAny + if n, err = recvfrom(fd, p, flags, &rsa, &socklen); err != nil { + return + } + pp := (*RawSockaddrInet6)(unsafe.Pointer(&rsa)) + port := (*[2]byte)(unsafe.Pointer(&pp.Port)) + from.Port = int(port[0])<<8 + int(port[1]) + from.ZoneId = pp.Scope_id + from.Addr = pp.Addr + return +} + +func recvmsgInet4(fd int, p, oob []byte, flags int, from *SockaddrInet4) (n, oobn int, recvflags int, err error) { + var rsa RawSockaddrAny + n, oobn, recvflags, err = recvmsgRaw(fd, p, oob, flags, &rsa) + if err != nil { + return + } + pp := (*RawSockaddrInet4)(unsafe.Pointer(&rsa)) + port := (*[2]byte)(unsafe.Pointer(&pp.Port)) + from.Port = int(port[0])<<8 + int(port[1]) + from.Addr = pp.Addr + return +} + +func recvmsgInet6(fd int, p, oob []byte, flags int, from *SockaddrInet6) (n, oobn int, recvflags int, err error) { + var rsa RawSockaddrAny + n, oobn, recvflags, err = recvmsgRaw(fd, p, oob, flags, &rsa) + if err != nil { + return + } + pp := (*RawSockaddrInet6)(unsafe.Pointer(&rsa)) + port := (*[2]byte)(unsafe.Pointer(&pp.Port)) + from.Port = int(port[0])<<8 + int(port[1]) + from.ZoneId = pp.Scope_id + from.Addr = pp.Addr + return +} + +func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) { + var rsa RawSockaddrAny + n, oobn, recvflags, err = recvmsgRaw(fd, p, oob, flags, &rsa) + // source address is only specified if the socket is unconnected + if rsa.Addr.Family != AF_UNSPEC { + from, err = anyToSockaddr(&rsa) + } + return +} + +func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) { + _, err = SendmsgN(fd, p, oob, to, flags) + return +} + +func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) { + var ptr *RawSockaddrAny + var salen Socklen_t + if to != nil { + ptr, salen, err = to.sockaddr() + if err != nil { + return 0, err + } + } + return sendmsgN(fd, p, oob, ptr, salen, flags) +} + +func sendmsgNInet4(fd int, p, oob []byte, to *SockaddrInet4, flags int) (n int, err error) { + ptr, salen, err := to.sockaddr() + if err != nil { + return 0, err + } + return sendmsgN(fd, p, oob, ptr, salen, flags) +} + +func sendmsgNInet6(fd int, p, oob []byte, to *SockaddrInet6, flags int) (n int, err error) { + ptr, salen, err := to.sockaddr() + if err != nil { + return 0, err + } + return sendmsgN(fd, p, oob, ptr, salen, flags) +} + +func sendtoInet4(fd int, p []byte, flags int, to *SockaddrInet4) (err error) { + ptr, n, err := to.sockaddr() + if err != nil { + return err + } + return sendto(fd, p, flags, ptr, n) +} + +func sendtoInet6(fd int, p []byte, flags int, to *SockaddrInet6) (err error) { + ptr, n, err := to.sockaddr() + if err != nil { + return err + } + return sendto(fd, p, flags, ptr, n) +} + func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) { ptr, n, err := to.sockaddr() if err != nil { @@ -340,9 +465,8 @@ func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) { return sendto(fd, p, flags, ptr, n) } -func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) { +func recvmsgRaw(fd int, p, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) { var msg Msghdr - var rsa RawSockaddrAny msg.Name = (*byte)(unsafe.Pointer(&rsa)) msg.Namelen = uint32(SizeofSockaddrAny) var iov Iovec @@ -372,30 +496,12 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from } oobn = int(msg.Controllen) recvflags = int(msg.Flags) - // source address is only specified if the socket is unconnected - if rsa.Addr.Family != AF_UNSPEC { - from, err = anyToSockaddr(&rsa) - } - return -} - -func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) { - _, err = SendmsgN(fd, p, oob, to, flags) return } -func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) { - var ptr *RawSockaddrAny - var salen Socklen_t - if to != nil { - var err error - ptr, salen, err = to.sockaddr() - if err != nil { - return 0, err - } - } +func sendmsgN(fd int, p, oob []byte, to *RawSockaddrAny, salen Socklen_t, flags int) (n int, err error) { var msg Msghdr - msg.Name = (*byte)(unsafe.Pointer(ptr)) + msg.Name = (*byte)(unsafe.Pointer(to)) msg.Namelen = uint32(salen) var iov Iovec if len(p) > 0 { diff --git a/libgo/go/syscall/syscall_dragonfly.go b/libgo/go/syscall/syscall_dragonfly.go index 930bb46..4b4ed77 100644 --- a/libgo/go/syscall/syscall_dragonfly.go +++ b/libgo/go/syscall/syscall_dragonfly.go @@ -9,6 +9,8 @@ import ( "unsafe" ) +const _SYS_DUP3 = 0 + // See version list in https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/sys/param.h var ( osreldateOnce sync.Once diff --git a/libgo/go/syscall/syscall_freebsd_test.go b/libgo/go/syscall/syscall_freebsd_test.go index 89c7959..f04b12b 100644 --- a/libgo/go/syscall/syscall_freebsd_test.go +++ b/libgo/go/syscall/syscall_freebsd_test.go @@ -3,12 +3,12 @@ // license that can be found in the LICENSE file. //go:build freebsd -// +build freebsd package syscall_test import ( "fmt" + "os" "syscall" "testing" "unsafe" @@ -53,3 +53,13 @@ func TestConvertFromDirent11(t *testing.T) { } } } + +func TestMain(m *testing.M) { + if os.Getenv("GO_DEATHSIG_PARENT") == "1" { + deathSignalParent() + } else if os.Getenv("GO_DEATHSIG_CHILD") == "1" { + deathSignalChild() + } + + os.Exit(m.Run()) +} diff --git a/libgo/go/syscall/syscall_js.go b/libgo/go/syscall/syscall_js.go index ed70d62..cd95499 100644 --- a/libgo/go/syscall/syscall_js.go +++ b/libgo/go/syscall/syscall_js.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build js && wasm -// +build js,wasm package syscall diff --git a/libgo/go/syscall/syscall_linux_mipsx.go b/libgo/go/syscall/syscall_linux_mipsx.go index 1df7a5f..809775f 100644 --- a/libgo/go/syscall/syscall_linux_mipsx.go +++ b/libgo/go/syscall/syscall_linux_mipsx.go @@ -3,8 +3,6 @@ // license that can be found in the LICENSE file. //go:build linux && (mips || mipsle || mips64 || mips64le || mips64p32 || mips64p32le) -// +build linux -// +build mips mipsle mips64 mips64le mips64p32 mips64p32le package syscall diff --git a/libgo/go/syscall/syscall_linux_test.go b/libgo/go/syscall/syscall_linux_test.go index fd826e9..6be48e2 100644 --- a/libgo/go/syscall/syscall_linux_test.go +++ b/libgo/go/syscall/syscall_linux_test.go @@ -5,13 +5,11 @@ package syscall_test import ( - "bufio" "fmt" "io" "io/fs" "os" "os/exec" - "os/signal" "path/filepath" "runtime" "sort" @@ -19,7 +17,6 @@ import ( "strings" "syscall" "testing" - "time" "unsafe" ) @@ -153,120 +150,6 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } -func TestLinuxDeathSignal(t *testing.T) { - if os.Getuid() != 0 { - t.Skip("skipping root only test") - } - - // Copy the test binary to a location that a non-root user can read/execute - // after we drop privileges - tempDir, err := os.MkdirTemp("", "TestDeathSignal") - if err != nil { - t.Fatalf("cannot create temporary directory: %v", err) - } - defer os.RemoveAll(tempDir) - os.Chmod(tempDir, 0755) - - tmpBinary := filepath.Join(tempDir, filepath.Base(os.Args[0])) - - src, err := os.Open(os.Args[0]) - if err != nil { - t.Fatalf("cannot open binary %q, %v", os.Args[0], err) - } - defer src.Close() - - dst, err := os.OpenFile(tmpBinary, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755) - if err != nil { - t.Fatalf("cannot create temporary binary %q, %v", tmpBinary, err) - } - if _, err := io.Copy(dst, src); err != nil { - t.Fatalf("failed to copy test binary to %q, %v", tmpBinary, err) - } - err = dst.Close() - if err != nil { - t.Fatalf("failed to close test binary %q, %v", tmpBinary, err) - } - - cmd := exec.Command(tmpBinary) - cmd.Env = append(os.Environ(), "GO_DEATHSIG_PARENT=1") - chldStdin, err := cmd.StdinPipe() - if err != nil { - t.Fatalf("failed to create new stdin pipe: %v", err) - } - chldStdout, err := cmd.StdoutPipe() - if err != nil { - t.Fatalf("failed to create new stdout pipe: %v", err) - } - cmd.Stderr = os.Stderr - - err = cmd.Start() - defer cmd.Wait() - if err != nil { - t.Fatalf("failed to start first child process: %v", err) - } - - chldPipe := bufio.NewReader(chldStdout) - - if got, err := chldPipe.ReadString('\n'); got == "start\n" { - syscall.Kill(cmd.Process.Pid, syscall.SIGTERM) - - go func() { - time.Sleep(5 * time.Second) - chldStdin.Close() - }() - - want := "ok\n" - if got, err = chldPipe.ReadString('\n'); got != want { - t.Fatalf("expected %q, received %q, %v", want, got, err) - } - } else { - t.Fatalf("did not receive start from child, received %q, %v", got, err) - } -} - -func deathSignalParent() { - cmd := exec.Command(os.Args[0]) - cmd.Env = append(os.Environ(), - "GO_DEATHSIG_PARENT=", - "GO_DEATHSIG_CHILD=1", - ) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - attrs := syscall.SysProcAttr{ - Pdeathsig: syscall.SIGUSR1, - // UID/GID 99 is the user/group "nobody" on RHEL/Fedora and is - // unused on Ubuntu - Credential: &syscall.Credential{Uid: 99, Gid: 99}, - } - cmd.SysProcAttr = &attrs - - err := cmd.Start() - if err != nil { - fmt.Fprintf(os.Stderr, "death signal parent error: %v\n", err) - os.Exit(1) - } - cmd.Wait() - os.Exit(0) -} - -func deathSignalChild() { - c := make(chan os.Signal, 1) - signal.Notify(c, syscall.SIGUSR1) - go func() { - <-c - fmt.Println("ok") - os.Exit(0) - }() - fmt.Println("start") - - buf := make([]byte, 32) - os.Stdin.Read(buf) - - // We expected to be signaled before stdin closed - fmt.Println("not ok") - os.Exit(1) -} - func TestParseNetlinkMessage(t *testing.T) { for i, b := range [][]byte{ {103, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 5, 8, 0, 3, diff --git a/libgo/go/syscall/syscall_ptrace_test.go b/libgo/go/syscall/syscall_ptrace_test.go index 45729d9..5b128de 100644 --- a/libgo/go/syscall/syscall_ptrace_test.go +++ b/libgo/go/syscall/syscall_ptrace_test.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd -// +build darwin dragonfly freebsd linux netbsd openbsd package syscall_test diff --git a/libgo/go/syscall/syscall_solaris.go b/libgo/go/syscall/syscall_solaris.go index 673ba82..13c60a4 100644 --- a/libgo/go/syscall/syscall_solaris.go +++ b/libgo/go/syscall/syscall_solaris.go @@ -6,6 +6,8 @@ package syscall import "unsafe" +const _F_DUP2FD_CLOEXEC = F_DUP2FD_CLOEXEC + func (ts *Timestruc) Unix() (sec int64, nsec int64) { return int64(ts.Sec), int64(ts.Nsec) } diff --git a/libgo/go/syscall/syscall_unix.go b/libgo/go/syscall/syscall_unix.go index 730cbfa..bd9b79c 100644 --- a/libgo/go/syscall/syscall_unix.go +++ b/libgo/go/syscall/syscall_unix.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris -// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris package syscall @@ -157,6 +156,9 @@ func Read(fd int, p []byte) (n int, err error) { if msanenabled && n > 0 { msanWrite(unsafe.Pointer(&p[0]), n) } + if asanenabled && n > 0 { + asanWrite(unsafe.Pointer(&p[0]), n) + } return } @@ -178,6 +180,9 @@ func Write(fd int, p []byte) (n int, err error) { if msanenabled && n > 0 { msanRead(unsafe.Pointer(&p[0]), n) } + if asanenabled && n > 0 { + asanRead(unsafe.Pointer(&p[0]), n) + } return } diff --git a/libgo/go/syscall/syscall_unix_test.go b/libgo/go/syscall/syscall_unix_test.go index d3d4673..205c600 100644 --- a/libgo/go/syscall/syscall_unix_test.go +++ b/libgo/go/syscall/syscall_unix_test.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris -// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package syscall_test @@ -87,16 +86,24 @@ func TestFcntlFlock(t *testing.T) { if err != nil { t.Fatalf("Open failed: %v", err) } - defer syscall.Close(fd) - if err := syscall.Ftruncate(fd, 1<<20); err != nil { + // f takes ownership of fd, and will close it. + // + // N.B. This defer is also necessary to keep f alive + // while we use its fd, preventing its finalizer from + // executing. + f := os.NewFile(uintptr(fd), name) + defer f.Close() + + if err := syscall.Ftruncate(int(f.Fd()), 1<<20); err != nil { t.Fatalf("Ftruncate(1<<20) failed: %v", err) } - if err := syscall.FcntlFlock(uintptr(fd), syscall.F_SETLK, &flock); err != nil { + if err := syscall.FcntlFlock(f.Fd(), syscall.F_SETLK, &flock); err != nil { t.Fatalf("FcntlFlock(F_SETLK) failed: %v", err) } + cmd := exec.Command(os.Args[0], "-test.run=^TestFcntlFlock$") cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1") - cmd.ExtraFiles = []*os.File{os.NewFile(uintptr(fd), name)} + cmd.ExtraFiles = []*os.File{f} out, err := cmd.CombinedOutput() if len(out) > 0 || err != nil { t.Fatalf("child process: %q, %v", out, err) @@ -254,6 +261,10 @@ func passFDChild() { fmt.Printf("TempFile: %v", err) return } + // N.B. This defer is also necessary to keep f alive + // while we use its fd, preventing its finalizer from + // executing. + defer f.Close() f.Write([]byte("Hello from child process!\n")) f.Seek(0, io.SeekStart) diff --git a/libgo/go/syscall/tables_js.go b/libgo/go/syscall/tables_js.go index 64d9584..78a1e71 100644 --- a/libgo/go/syscall/tables_js.go +++ b/libgo/go/syscall/tables_js.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build js && wasm -// +build js,wasm package syscall diff --git a/libgo/go/syscall/time_fake.go b/libgo/go/syscall/time_fake.go index cf88aeb..b60fe60 100644 --- a/libgo/go/syscall/time_fake.go +++ b/libgo/go/syscall/time_fake.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build faketime -// +build faketime package syscall diff --git a/libgo/go/syscall/time_nofake.go b/libgo/go/syscall/time_nofake.go index 5eaa2da..231875d 100644 --- a/libgo/go/syscall/time_nofake.go +++ b/libgo/go/syscall/time_nofake.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build !faketime -// +build !faketime package syscall diff --git a/libgo/go/syscall/timestruct.go b/libgo/go/syscall/timestruct.go index f22c282..3a98985 100644 --- a/libgo/go/syscall/timestruct.go +++ b/libgo/go/syscall/timestruct.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris -// +build aix darwin dragonfly freebsd hurd js,wasm linux netbsd openbsd solaris package syscall |