aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/syscall
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2020-12-23 09:57:37 -0800
committerIan Lance Taylor <iant@golang.org>2020-12-30 15:13:24 -0800
commitcfcbb4227fb20191e04eb8d7766ae6202f526afd (patch)
treee2effea96f6f204451779f044415c2385e45042b /libgo/go/syscall
parent0696141107d61483f38482b941549959a0d7f613 (diff)
downloadgcc-cfcbb4227fb20191e04eb8d7766ae6202f526afd.zip
gcc-cfcbb4227fb20191e04eb8d7766ae6202f526afd.tar.gz
gcc-cfcbb4227fb20191e04eb8d7766ae6202f526afd.tar.bz2
libgo: update to Go1.16beta1 release
This does not yet include support for the //go:embed directive added in this release. * Makefile.am (check-runtime): Don't create check-runtime-dir. (mostlyclean-local): Don't remove check-runtime-dir. (check-go-tool, check-vet): Copy in go.mod and modules.txt. (check-cgo-test, check-carchive-test): Add go.mod file. * Makefile.in: Regenerate. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/280172
Diffstat (limited to 'libgo/go/syscall')
-rw-r--r--libgo/go/syscall/dirent_test.go9
-rw-r--r--libgo/go/syscall/exec_linux_test.go15
-rw-r--r--libgo/go/syscall/exec_unix.go4
-rw-r--r--libgo/go/syscall/exec_windows.go81
-rw-r--r--libgo/go/syscall/exec_windows_test.go43
-rw-r--r--libgo/go/syscall/export_unix_test.go2
-rw-r--r--libgo/go/syscall/fs_js.go7
-rw-r--r--libgo/go/syscall/getdirentries_test.go5
-rw-r--r--libgo/go/syscall/libcall_posix.go6
-rw-r--r--libgo/go/syscall/mkasm_darwin.go9
-rw-r--r--libgo/go/syscall/setuidgid_32_linux.go6
-rw-r--r--libgo/go/syscall/setuidgid_linux.go6
-rw-r--r--libgo/go/syscall/signame.c3
-rw-r--r--libgo/go/syscall/sockcmsg_unix_other.go6
-rw-r--r--libgo/go/syscall/syscall.go12
-rw-r--r--libgo/go/syscall/syscall_errno.go4
-rw-r--r--libgo/go/syscall/syscall_js.go2
-rw-r--r--libgo/go/syscall/syscall_linux.go34
-rw-r--r--libgo/go/syscall/syscall_linux_386.go3
-rw-r--r--libgo/go/syscall/syscall_linux_test.go268
-rw-r--r--libgo/go/syscall/syscall_unix.go2
-rw-r--r--libgo/go/syscall/syscall_unix_test.go25
-rw-r--r--libgo/go/syscall/timestruct.go12
23 files changed, 463 insertions, 101 deletions
diff --git a/libgo/go/syscall/dirent_test.go b/libgo/go/syscall/dirent_test.go
index f631533..7dac98f 100644
--- a/libgo/go/syscall/dirent_test.go
+++ b/libgo/go/syscall/dirent_test.go
@@ -9,7 +9,6 @@ package syscall_test
import (
"bytes"
"fmt"
- "io/ioutil"
"os"
"path/filepath"
"runtime"
@@ -27,7 +26,7 @@ func TestDirent(t *testing.T) {
filenameMinSize = 11
)
- d, err := ioutil.TempDir("", "dirent-test")
+ d, err := os.MkdirTemp("", "dirent-test")
if err != nil {
t.Fatalf("tempdir: %v", err)
}
@@ -36,7 +35,7 @@ func TestDirent(t *testing.T) {
for i, c := range []byte("0123456789") {
name := string(bytes.Repeat([]byte{c}, filenameMinSize+i))
- err = ioutil.WriteFile(filepath.Join(d, name), nil, 0644)
+ err = os.WriteFile(filepath.Join(d, name), nil, 0644)
if err != nil {
t.Fatalf("writefile: %v", err)
}
@@ -93,7 +92,7 @@ func TestDirentRepeat(t *testing.T) {
}
// Make a directory containing N files
- d, err := ioutil.TempDir("", "direntRepeat-test")
+ d, err := os.MkdirTemp("", "direntRepeat-test")
if err != nil {
t.Fatalf("tempdir: %v", err)
}
@@ -104,7 +103,7 @@ func TestDirentRepeat(t *testing.T) {
files = append(files, fmt.Sprintf("file%d", i))
}
for _, file := range files {
- err = ioutil.WriteFile(filepath.Join(d, file), []byte("contents"), 0644)
+ err = os.WriteFile(filepath.Join(d, file), []byte("contents"), 0644)
if err != nil {
t.Fatalf("writefile: %v", err)
}
diff --git a/libgo/go/syscall/exec_linux_test.go b/libgo/go/syscall/exec_linux_test.go
index 1a44f04..bbab36d 100644
--- a/libgo/go/syscall/exec_linux_test.go
+++ b/libgo/go/syscall/exec_linux_test.go
@@ -11,7 +11,6 @@ import (
"fmt"
"internal/testenv"
"io"
- "io/ioutil"
"os"
"os/exec"
"os/user"
@@ -65,7 +64,7 @@ func skipNoUserNamespaces(t *testing.T) {
func skipUnprivilegedUserClone(t *testing.T) {
// Skip the test if the sysctl that prevents unprivileged user
// from creating user namespaces is enabled.
- data, errRead := ioutil.ReadFile("/proc/sys/kernel/unprivileged_userns_clone")
+ data, errRead := os.ReadFile("/proc/sys/kernel/unprivileged_userns_clone")
if errRead != nil || len(data) < 1 || data[0] == '0' {
t.Skip("kernel prohibits user namespace in unprivileged process")
}
@@ -98,7 +97,7 @@ func checkUserNS(t *testing.T) {
// On Centos 7 make sure they set the kernel parameter user_namespace=1
// See issue 16283 and 20796.
if _, err := os.Stat("/sys/module/user_namespace/parameters/enable"); err == nil {
- buf, _ := ioutil.ReadFile("/sys/module/user_namespace/parameters/enabled")
+ buf, _ := os.ReadFile("/sys/module/user_namespace/parameters/enabled")
if !strings.HasPrefix(string(buf), "Y") {
t.Skip("kernel doesn't support user namespaces")
}
@@ -106,7 +105,7 @@ func checkUserNS(t *testing.T) {
// On Centos 7.5+, user namespaces are disabled if user.max_user_namespaces = 0
if _, err := os.Stat("/proc/sys/user/max_user_namespaces"); err == nil {
- buf, errRead := ioutil.ReadFile("/proc/sys/user/max_user_namespaces")
+ buf, errRead := os.ReadFile("/proc/sys/user/max_user_namespaces")
if errRead == nil && buf[0] == '0' {
t.Skip("kernel doesn't support user namespaces")
}
@@ -226,7 +225,7 @@ func TestUnshare(t *testing.T) {
t.Fatal(err)
}
- orig, err := ioutil.ReadFile(path)
+ orig, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
@@ -349,7 +348,7 @@ func TestUnshareMountNameSpace(t *testing.T) {
t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace")
}
- d, err := ioutil.TempDir("", "unshare")
+ d, err := os.MkdirTemp("", "unshare")
if err != nil {
t.Fatalf("tempdir: %v", err)
}
@@ -391,7 +390,7 @@ func TestUnshareMountNameSpaceChroot(t *testing.T) {
t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace")
}
- d, err := ioutil.TempDir("", "unshare")
+ d, err := os.MkdirTemp("", "unshare")
if err != nil {
t.Fatalf("tempdir: %v", err)
}
@@ -599,7 +598,7 @@ func testAmbientCaps(t *testing.T, userns bool) {
}
// Copy the test binary to a temporary location which is readable by nobody.
- f, err := ioutil.TempFile("", "gotest")
+ f, err := os.CreateTemp("", "gotest")
if err != nil {
t.Fatal(err)
}
diff --git a/libgo/go/syscall/exec_unix.go b/libgo/go/syscall/exec_unix.go
index 7c6d942..2441f5e 100644
--- a/libgo/go/syscall/exec_unix.go
+++ b/libgo/go/syscall/exec_unix.go
@@ -347,9 +347,9 @@ func Exec(argv0 string, argv []string, envv []string) (err error) {
var err1 error
if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" || runtime.GOOS == "aix" || runtime.GOOS == "hurd" {
- // RawSyscall should never be used on Solaris or AIX.
+ // RawSyscall should never be used on Solaris, illumos, or AIX.
err1 = raw_execve(argv0p, &argvp[0], &envvp[0])
- } else if runtime.GOOS == "darwin" {
+ } else if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
// Similarly on Darwin.
err1 = execveDarwin(argv0p, &argvp[0], &envvp[0])
} else {
diff --git a/libgo/go/syscall/exec_windows.go b/libgo/go/syscall/exec_windows.go
index 8d6141c..46cbd75 100644
--- a/libgo/go/syscall/exec_windows.go
+++ b/libgo/go/syscall/exec_windows.go
@@ -25,73 +25,89 @@ var ForkLock sync.RWMutex
// but only if there is space or tab inside s.
func EscapeArg(s string) string {
if len(s) == 0 {
- return "\"\""
+ return `""`
}
- n := len(s)
+ for i := 0; i < len(s); i++ {
+ switch s[i] {
+ case '"', '\\', ' ', '\t':
+ // Some escaping required.
+ b := make([]byte, 0, len(s)+2)
+ b = appendEscapeArg(b, s)
+ return string(b)
+ }
+ }
+ return s
+}
+
+// appendEscapeArg escapes the string s, as per escapeArg,
+// appends the result to b, and returns the updated slice.
+func appendEscapeArg(b []byte, s string) []byte {
+ if len(s) == 0 {
+ return append(b, `""`...)
+ }
+
+ needsBackslash := false
hasSpace := false
for i := 0; i < len(s); i++ {
switch s[i] {
case '"', '\\':
- n++
+ needsBackslash = true
case ' ', '\t':
hasSpace = true
}
}
- if hasSpace {
- n += 2
+
+ if !needsBackslash && !hasSpace {
+ // No special handling required; normal case.
+ return append(b, s...)
}
- if n == len(s) {
- return s
+ if !needsBackslash {
+ // hasSpace is true, so we need to quote the string.
+ b = append(b, '"')
+ b = append(b, s...)
+ return append(b, '"')
}
- qs := make([]byte, n)
- j := 0
if hasSpace {
- qs[j] = '"'
- j++
+ b = append(b, '"')
}
slashes := 0
for i := 0; i < len(s); i++ {
- switch s[i] {
+ c := s[i]
+ switch c {
default:
slashes = 0
- qs[j] = s[i]
case '\\':
slashes++
- qs[j] = s[i]
case '"':
for ; slashes > 0; slashes-- {
- qs[j] = '\\'
- j++
+ b = append(b, '\\')
}
- qs[j] = '\\'
- j++
- qs[j] = s[i]
+ b = append(b, '\\')
}
- j++
+ b = append(b, c)
}
if hasSpace {
for ; slashes > 0; slashes-- {
- qs[j] = '\\'
- j++
+ b = append(b, '\\')
}
- qs[j] = '"'
- j++
+ b = append(b, '"')
}
- return string(qs[:j])
+
+ return b
}
// makeCmdLine builds a command line out of args by escaping "special"
// characters and joining the arguments with spaces.
func makeCmdLine(args []string) string {
- var s string
+ var b []byte
for _, v := range args {
- if s != "" {
- s += " "
+ if len(b) > 0 {
+ b = append(b, ' ')
}
- s += EscapeArg(v)
+ b = appendEscapeArg(b, v)
}
- return s
+ return string(b)
}
// createEnvBlock converts an array of environment strings into
@@ -225,6 +241,7 @@ type SysProcAttr struct {
Token Token // if set, runs new process in the security context represented by the token
ProcessAttributes *SecurityAttributes // if set, applies these security attributes as the descriptor for the new process
ThreadAttributes *SecurityAttributes // if set, applies these security attributes as the descriptor for the main thread of the new process
+ NoInheritHandles bool // if set, each inheritable handle in the calling process is not inherited by the new process
}
var zeroProcAttr ProcAttr
@@ -325,9 +342,9 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT
if sys.Token != 0 {
- err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, true, flags, createEnvBlock(attr.Env), dirp, si, pi)
+ err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, si, pi)
} else {
- err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, true, flags, createEnvBlock(attr.Env), dirp, si, pi)
+ err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, !sys.NoInheritHandles, flags, createEnvBlock(attr.Env), dirp, si, pi)
}
if err != nil {
return 0, 0, err
diff --git a/libgo/go/syscall/exec_windows_test.go b/libgo/go/syscall/exec_windows_test.go
new file mode 100644
index 0000000..eda1d36
--- /dev/null
+++ b/libgo/go/syscall/exec_windows_test.go
@@ -0,0 +1,43 @@
+// Copyright 2020 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_test
+
+import (
+ "syscall"
+ "testing"
+)
+
+func TestEscapeArg(t *testing.T) {
+ var tests = []struct {
+ input, output string
+ }{
+ {``, `""`},
+ {`a`, `a`},
+ {` `, `" "`},
+ {`\`, `\`},
+ {`"`, `\"`},
+ {`\"`, `\\\"`},
+ {`\\"`, `\\\\\"`},
+ {`\\ `, `"\\ "`},
+ {` \\`, `" \\\\"`},
+ {`a `, `"a "`},
+ {`C:\`, `C:\`},
+ {`C:\Program Files (x32)\Common\`, `"C:\Program Files (x32)\Common\\"`},
+ {`C:\Users\Игорь\`, `C:\Users\Игорь\`},
+ {`Андрей\file`, `Андрей\file`},
+ {`C:\Windows\temp`, `C:\Windows\temp`},
+ {`c:\temp\newfile`, `c:\temp\newfile`},
+ {`\\?\C:\Windows`, `\\?\C:\Windows`},
+ {`\\?\`, `\\?\`},
+ {`\\.\C:\Windows\`, `\\.\C:\Windows\`},
+ {`\\server\share\file`, `\\server\share\file`},
+ {`\\newserver\tempshare\really.txt`, `\\newserver\tempshare\really.txt`},
+ }
+ for _, test := range tests {
+ if got := syscall.EscapeArg(test.input); got != test.output {
+ t.Errorf("EscapeArg(%#q) = %#q, want %#q", test.input, got, test.output)
+ }
+ }
+}
diff --git a/libgo/go/syscall/export_unix_test.go b/libgo/go/syscall/export_unix_test.go
index 4d67be9..1b78756 100644
--- a/libgo/go/syscall/export_unix_test.go
+++ b/libgo/go/syscall/export_unix_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 darwin dragonfly freebsd hurd linux netbsd openbsd solaris
+// +build dragonfly freebsd hurd linux netbsd openbsd solaris
package syscall
diff --git a/libgo/go/syscall/fs_js.go b/libgo/go/syscall/fs_js.go
index 262ec28..673feea 100644
--- a/libgo/go/syscall/fs_js.go
+++ b/libgo/go/syscall/fs_js.go
@@ -8,7 +8,6 @@ package syscall
import (
"errors"
- "io"
"sync"
"syscall/js"
)
@@ -456,11 +455,11 @@ func Seek(fd int, offset int64, whence int) (int64, error) {
var newPos int64
switch whence {
- case io.SeekStart:
+ case 0:
newPos = offset
- case io.SeekCurrent:
+ case 1:
newPos = f.pos + offset
- case io.SeekEnd:
+ case 2:
var st Stat_t
if err := Fstat(fd, &st); err != nil {
return 0, err
diff --git a/libgo/go/syscall/getdirentries_test.go b/libgo/go/syscall/getdirentries_test.go
index 2a3419c..66bb8ac 100644
--- a/libgo/go/syscall/getdirentries_test.go
+++ b/libgo/go/syscall/getdirentries_test.go
@@ -8,7 +8,6 @@ package syscall_test
import (
"fmt"
- "io/ioutil"
"os"
"path/filepath"
"sort"
@@ -29,7 +28,7 @@ func testGetdirentries(t *testing.T, count int) {
if count > 100 && testing.Short() && os.Getenv("GO_BUILDER_NAME") == "" {
t.Skip("skipping in -short mode")
}
- d, err := ioutil.TempDir("", "getdirentries-test")
+ d, err := os.MkdirTemp("", "getdirentries-test")
if err != nil {
t.Fatalf("Tempdir: %v", err)
}
@@ -41,7 +40,7 @@ func testGetdirentries(t *testing.T, count int) {
// Make files in the temp directory
for _, name := range names {
- err := ioutil.WriteFile(filepath.Join(d, name), []byte("data"), 0)
+ err := os.WriteFile(filepath.Join(d, name), []byte("data"), 0)
if err != nil {
t.Fatalf("WriteFile: %v", err)
}
diff --git a/libgo/go/syscall/libcall_posix.go b/libgo/go/syscall/libcall_posix.go
index 31d6bf1..f37457a 100644
--- a/libgo/go/syscall/libcall_posix.go
+++ b/libgo/go/syscall/libcall_posix.go
@@ -292,6 +292,9 @@ func Gettimeofday(tv *Timeval) (err error) {
//sysnb Setgid(gid int) (err error)
//setgid(gid Gid_t) _C_int
+//sysnb Setegid(uid int) (err error)
+//setegid(uid Uid_t) _C_int
+
//sysnb Setregid(rgid int, egid int) (err error)
//setregid(rgid Gid_t, egid Gid_t) _C_int
@@ -317,6 +320,9 @@ func Settimeofday(tv *Timeval) (err error) {
//sysnb Setuid(uid int) (err error)
//setuid(uid Uid_t) _C_int
+//sysnb Seteuid(uid int) (err error)
+//seteuid(uid Uid_t) _C_int
+
//sys Symlink(oldpath string, newpath string) (err error)
//symlink(oldpath *byte, newpath *byte) _C_int
diff --git a/libgo/go/syscall/mkasm_darwin.go b/libgo/go/syscall/mkasm_darwin.go
index f6f75f9..1783387 100644
--- a/libgo/go/syscall/mkasm_darwin.go
+++ b/libgo/go/syscall/mkasm_darwin.go
@@ -11,23 +11,22 @@ package main
import (
"bytes"
"fmt"
- "io/ioutil"
"log"
"os"
"strings"
)
func main() {
- in1, err := ioutil.ReadFile("syscall_darwin.go")
+ in1, err := os.ReadFile("syscall_darwin.go")
if err != nil {
log.Fatalf("can't open syscall_darwin.go: %s", err)
}
arch := os.Args[1]
- in2, err := ioutil.ReadFile(fmt.Sprintf("syscall_darwin_%s.go", arch))
+ in2, err := os.ReadFile(fmt.Sprintf("syscall_darwin_%s.go", arch))
if err != nil {
log.Fatalf("can't open syscall_darwin_%s.go: %s", arch, err)
}
- in3, err := ioutil.ReadFile(fmt.Sprintf("zsyscall_darwin_%s.go", arch))
+ in3, err := os.ReadFile(fmt.Sprintf("zsyscall_darwin_%s.go", arch))
if err != nil {
log.Fatalf("can't open zsyscall_darwin_%s.go: %s", arch, err)
}
@@ -51,7 +50,7 @@ func main() {
fmt.Fprintf(&out, "\tJMP\t%s(SB)\n", fn)
}
}
- err = ioutil.WriteFile(fmt.Sprintf("zsyscall_darwin_%s.s", arch), out.Bytes(), 0644)
+ err = os.WriteFile(fmt.Sprintf("zsyscall_darwin_%s.s", arch), out.Bytes(), 0644)
if err != nil {
log.Fatalf("can't write zsyscall_darwin_%s.s: %s", arch, err)
}
diff --git a/libgo/go/syscall/setuidgid_32_linux.go b/libgo/go/syscall/setuidgid_32_linux.go
index 1fe7120..b0b7f61 100644
--- a/libgo/go/syscall/setuidgid_32_linux.go
+++ b/libgo/go/syscall/setuidgid_32_linux.go
@@ -12,4 +12,10 @@ const (
sys_SETGID = SYS_SETGID32
sys_SETUID = SYS_SETUID32
+
+ sys_SETREGID = SYS_SETREGID32
+ sys_SETREUID = SYS_SETREUID32
+
+ sys_SETRESGID = SYS_SETRESGID32
+ sys_SETRESUID = SYS_SETRESUID32
)
diff --git a/libgo/go/syscall/setuidgid_linux.go b/libgo/go/syscall/setuidgid_linux.go
index 22fa334..38c83c9 100644
--- a/libgo/go/syscall/setuidgid_linux.go
+++ b/libgo/go/syscall/setuidgid_linux.go
@@ -12,4 +12,10 @@ const (
sys_SETGID = SYS_SETGID
sys_SETUID = SYS_SETUID
+
+ sys_SETREGID = SYS_SETREGID
+ sys_SETREUID = SYS_SETREUID
+
+ sys_SETRESGID = SYS_SETRESGID
+ sys_SETRESUID = SYS_SETRESUID
)
diff --git a/libgo/go/syscall/signame.c b/libgo/go/syscall/signame.c
index dca92a9..e2e77cb 100644
--- a/libgo/go/syscall/signame.c
+++ b/libgo/go/syscall/signame.c
@@ -33,6 +33,9 @@ Signame (intgo sig)
len = __builtin_strlen (s);
data = runtime_mallocgc (len, nil, false);
__builtin_memcpy (data, s, len);
+ // lowercase first letter: Bad -> bad, but STREAM -> STREAM.
+ if ('A' <= data[0] && data[0] <= 'Z' && 'a' <= data[1] && data[1] <= 'z')
+ data[0] += 'a' - 'A';
ret.str = data;
ret.len = len;
return ret;
diff --git a/libgo/go/syscall/sockcmsg_unix_other.go b/libgo/go/syscall/sockcmsg_unix_other.go
index 3e7afe4..f5deeb4 100644
--- a/libgo/go/syscall/sockcmsg_unix_other.go
+++ b/libgo/go/syscall/sockcmsg_unix_other.go
@@ -20,7 +20,7 @@ func cmsgAlignOf(salen int) int {
case "aix":
// There is no alignment on AIX.
salign = 1
- case "darwin", "illumos", "solaris":
+ case "darwin", "ios", "illumos", "solaris":
// NOTE: It seems like 64-bit Darwin, Illumos and Solaris
// kernels still require 32-bit aligned access to network
// subsystem.
@@ -32,6 +32,10 @@ func cmsgAlignOf(salen int) int {
if runtime.GOARCH == "arm" {
salign = 8
}
+ // NetBSD aarch64 requires 128-bit alignment.
+ if runtime.GOOS == "netbsd" && runtime.GOARCH == "arm64" {
+ salign = 16
+ }
}
return (salen + salign - 1) & ^(salign - 1)
diff --git a/libgo/go/syscall/syscall.go b/libgo/go/syscall/syscall.go
index 4e1187b..fb41bcc 100644
--- a/libgo/go/syscall/syscall.go
+++ b/libgo/go/syscall/syscall.go
@@ -28,7 +28,7 @@ package syscall
import "unsafe"
-//go:generate go run golang.org/x/sys/windows/mkwinsyscall -systemdll -output zsyscall_windows.go syscall_windows.go security_windows.go
+//go:generate go run ./mksyscall_windows.go -systemdll -output zsyscall_windows.go syscall_windows.go security_windows.go
// StringByteSlice converts a string to a NUL-terminated []byte,
// If s contains a NUL byte this function panics instead of
@@ -83,24 +83,22 @@ var dummy *byte
const sizeofPtr uintptr = uintptr(unsafe.Sizeof(dummy))
-// Unix returns ts as the number of seconds and nanoseconds elapsed since the
-// Unix epoch.
+// Unix returns the time stored in ts as seconds plus nanoseconds.
func (ts *Timespec) Unix() (sec int64, nsec int64) {
return int64(ts.Sec), int64(ts.Nsec)
}
-// Unix returns tv as the number of seconds and nanoseconds elapsed since the
-// Unix epoch.
+// Unix returns the time stored in tv as seconds plus nanoseconds.
func (tv *Timeval) Unix() (sec int64, nsec int64) {
return int64(tv.Sec), int64(tv.Usec) * 1000
}
-// Nano returns ts as the number of nanoseconds elapsed since the Unix epoch.
+// Nano returns the time stored in ts as nanoseconds.
func (ts *Timespec) Nano() int64 {
return int64(ts.Sec)*1e9 + int64(ts.Nsec)
}
-// Nano returns tv as the number of nanoseconds elapsed since the Unix epoch.
+// Nano returns the time stored in tv as nanoseconds.
func (tv *Timeval) Nano() int64 {
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
}
diff --git a/libgo/go/syscall/syscall_errno.go b/libgo/go/syscall/syscall_errno.go
index 0d781de..4df198e 100644
--- a/libgo/go/syscall/syscall_errno.go
+++ b/libgo/go/syscall/syscall_errno.go
@@ -7,7 +7,7 @@ package syscall
import "internal/oserror"
// An Errno is an unsigned number describing an error condition.
-// It implements the error interface. The zero Errno is by convention
+// It implements the error interface. The zero Errno is by convention
// a non-error, so code to convert from Errno to error should use:
// err = nil
// if errno != 0 {
@@ -18,7 +18,7 @@ import "internal/oserror"
// using errors.Is. For example:
//
// _, _, err := syscall.Syscall(...)
-// if errors.Is(err, os.ErrNotExist) ...
+// if errors.Is(err, fs.ErrNotExist) ...
type Errno uintptr
func (e Errno) Error() string {
diff --git a/libgo/go/syscall/syscall_js.go b/libgo/go/syscall/syscall_js.go
index dfb4a27..0ab8c3f 100644
--- a/libgo/go/syscall/syscall_js.go
+++ b/libgo/go/syscall/syscall_js.go
@@ -49,7 +49,7 @@ const PathMax = 256
// using errors.Is. For example:
//
// _, _, err := syscall.Syscall(...)
-// if errors.Is(err, os.ErrNotExist) ...
+// if errors.Is(err, fs.ErrNotExist) ...
type Errno uintptr
func (e Errno) Error() string {
diff --git a/libgo/go/syscall/syscall_linux.go b/libgo/go/syscall/syscall_linux.go
new file mode 100644
index 0000000..3f32845
--- /dev/null
+++ b/libgo/go/syscall/syscall_linux.go
@@ -0,0 +1,34 @@
+// 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.
+
+package syscall
+
+// AllThreadsSyscall performs a syscall on each OS thread of the Go
+// runtime. It first invokes the syscall on one thread. Should that
+// invocation fail, it returns immediately with the error status.
+// Otherwise, it invokes the syscall on all of the remaining threads
+// in parallel. It will terminate the program if it observes any
+// invoked syscall's return value differs from that of the first
+// invocation.
+//
+// AllThreadsSyscall is intended for emulating simultaneous
+// process-wide state changes that require consistently modifying
+// per-thread state of the Go runtime.
+//
+// AllThreadsSyscall is unaware of any threads that are launched
+// explicitly by cgo linked code, so the function always returns
+// ENOTSUP in binaries that use cgo.
+//go:uintptrescapes
+func AllThreadsSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
+ return minus1, minus1, ENOTSUP
+}
+
+// AllThreadsSyscall6 is like AllThreadsSyscall, but extended to six
+// arguments.
+//go:uintptrescapes
+func AllThreadsSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
+ return minus1, minus1, ENOTSUP
+}
+
+const minus1 = ^uintptr(0)
diff --git a/libgo/go/syscall/syscall_linux_386.go b/libgo/go/syscall/syscall_linux_386.go
index 9abcab9..5a9f6d9 100644
--- a/libgo/go/syscall/syscall_linux_386.go
+++ b/libgo/go/syscall/syscall_linux_386.go
@@ -4,9 +4,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
-// so that go vet can check that they are correct.
-
package syscall
import "unsafe"
diff --git a/libgo/go/syscall/syscall_linux_test.go b/libgo/go/syscall/syscall_linux_test.go
index c12df4c..91448fd 100644
--- a/libgo/go/syscall/syscall_linux_test.go
+++ b/libgo/go/syscall/syscall_linux_test.go
@@ -8,7 +8,7 @@ import (
"bufio"
"fmt"
"io"
- "io/ioutil"
+ "io/fs"
"os"
"os/exec"
"os/signal"
@@ -29,7 +29,7 @@ func chtmpdir(t *testing.T) func() {
if err != nil {
t.Fatalf("chtmpdir: %v", err)
}
- d, err := ioutil.TempDir("", "test")
+ d, err := os.MkdirTemp("", "test")
if err != nil {
t.Fatalf("chtmpdir: %v", err)
}
@@ -159,7 +159,7 @@ func TestLinuxDeathSignal(t *testing.T) {
// Copy the test binary to a location that a non-root user can read/execute
// after we drop privileges
- tempDir, err := ioutil.TempDir("", "TestDeathSignal")
+ tempDir, err := os.MkdirTemp("", "TestDeathSignal")
if err != nil {
t.Fatalf("cannot create temporary directory: %v", err)
}
@@ -324,7 +324,7 @@ func TestSyscallNoError(t *testing.T) {
// Copy the test binary to a location that a non-root user can read/execute
// after we drop privileges
- tempDir, err := ioutil.TempDir("", "TestSyscallNoError")
+ tempDir, err := os.MkdirTemp("", "TestSyscallNoError")
if err != nil {
t.Fatalf("cannot create temporary directory: %v", err)
}
@@ -357,7 +357,7 @@ func TestSyscallNoError(t *testing.T) {
t.Fatalf("failed to chown test binary %q, %v", tmpBinary, err)
}
- err = os.Chmod(tmpBinary, 0755|os.ModeSetuid)
+ err = os.Chmod(tmpBinary, 0755|fs.ModeSetuid)
if err != nil {
t.Fatalf("failed to set setuid bit on test binary %q, %v", tmpBinary, err)
}
@@ -402,3 +402,261 @@ func syscallNoError() {
fmt.Println(uintptr(euid1), "/", int(e), "/", uintptr(euid2))
os.Exit(0)
}
+
+// reference uapi/linux/prctl.h
+const (
+ PR_GET_KEEPCAPS uintptr = 7
+ PR_SET_KEEPCAPS = 8
+)
+
+// TestAllThreadsSyscall tests that the go runtime can perform
+// syscalls that execute on all OSThreads - with which to support
+// POSIX semantics for security state changes.
+func TestAllThreadsSyscall(t *testing.T) {
+ if _, _, err := syscall.AllThreadsSyscall(syscall.SYS_PRCTL, PR_SET_KEEPCAPS, 0, 0); err == syscall.ENOTSUP {
+ t.Skip("AllThreadsSyscall disabled with cgo")
+ }
+
+ fns := []struct {
+ label string
+ fn func(uintptr) error
+ }{
+ {
+ label: "prctl<3-args>",
+ fn: func(v uintptr) error {
+ _, _, e := syscall.AllThreadsSyscall(syscall.SYS_PRCTL, PR_SET_KEEPCAPS, v, 0)
+ if e != 0 {
+ return e
+ }
+ return nil
+ },
+ },
+ {
+ label: "prctl<6-args>",
+ fn: func(v uintptr) error {
+ _, _, e := syscall.AllThreadsSyscall6(syscall.SYS_PRCTL, PR_SET_KEEPCAPS, v, 0, 0, 0, 0)
+ if e != 0 {
+ return e
+ }
+ return nil
+ },
+ },
+ }
+
+ waiter := func(q <-chan uintptr, r chan<- uintptr, once bool) {
+ for x := range q {
+ runtime.LockOSThread()
+ v, _, e := syscall.Syscall(syscall.SYS_PRCTL, PR_GET_KEEPCAPS, 0, 0)
+ if e != 0 {
+ t.Errorf("tid=%d prctl(PR_GET_KEEPCAPS) failed: %v", syscall.Gettid(), e)
+ } else if x != v {
+ t.Errorf("tid=%d prctl(PR_GET_KEEPCAPS) mismatch: got=%d want=%d", syscall.Gettid(), v, x)
+ }
+ r <- v
+ if once {
+ break
+ }
+ runtime.UnlockOSThread()
+ }
+ }
+
+ // launches per fns member.
+ const launches = 11
+ question := make(chan uintptr)
+ response := make(chan uintptr)
+ defer close(question)
+
+ routines := 0
+ for i, v := range fns {
+ for j := 0; j < launches; j++ {
+ // Add another goroutine - the closest thing
+ // we can do to encourage more OS thread
+ // creation - while the test is running. The
+ // actual thread creation may or may not be
+ // needed, based on the number of available
+ // unlocked OS threads at the time waiter
+ // calls runtime.LockOSThread(), but the goal
+ // of doing this every time through the loop
+ // is to race thread creation with v.fn(want)
+ // being executed. Via the once boolean we
+ // also encourage one in 5 waiters to return
+ // locked after participating in only one
+ // question response sequence. This allows the
+ // test to race thread destruction too.
+ once := routines%5 == 4
+ go waiter(question, response, once)
+
+ // Keep a count of how many goroutines are
+ // going to participate in the
+ // question/response test. This will count up
+ // towards 2*launches minus the count of
+ // routines that have been invoked with
+ // once=true.
+ routines++
+
+ // Decide what value we want to set the
+ // process-shared KEEPCAPS. Note, there is
+ // an explicit repeat of 0 when we change the
+ // variant of the syscall being used.
+ want := uintptr(j & 1)
+
+ // Invoke the AllThreadsSyscall* variant.
+ if err := v.fn(want); err != nil {
+ t.Errorf("[%d,%d] %s(PR_SET_KEEPCAPS, %d, ...): %v", i, j, v.label, j&1, err)
+ }
+
+ // At this point, we want all launched Go
+ // routines to confirm that they see the
+ // wanted value for KEEPCAPS.
+ for k := 0; k < routines; k++ {
+ question <- want
+ }
+
+ // At this point, we should have a large
+ // number of locked OS threads all wanting to
+ // reply.
+ for k := 0; k < routines; k++ {
+ if got := <-response; got != want {
+ t.Errorf("[%d,%d,%d] waiter result got=%d, want=%d", i, j, k, got, want)
+ }
+ }
+
+ // Provide an explicit opportunity for this Go
+ // routine to change Ms.
+ runtime.Gosched()
+
+ if once {
+ // One waiter routine will have exited.
+ routines--
+ }
+
+ // Whatever M we are now running on, confirm
+ // we see the wanted value too.
+ if v, _, e := syscall.Syscall(syscall.SYS_PRCTL, PR_GET_KEEPCAPS, 0, 0); e != 0 {
+ t.Errorf("[%d,%d] prctl(PR_GET_KEEPCAPS) failed: %v", i, j, e)
+ } else if v != want {
+ t.Errorf("[%d,%d] prctl(PR_GET_KEEPCAPS) gave wrong value: got=%v, want=1", i, j, v)
+ }
+ }
+ }
+}
+
+// compareStatus is used to confirm the contents of the thread
+// specific status files match expectations.
+func compareStatus(filter, expect string) error {
+ expected := filter + expect
+ pid := syscall.Getpid()
+ fs, err := os.ReadDir(fmt.Sprintf("/proc/%d/task", pid))
+ if err != nil {
+ return fmt.Errorf("unable to find %d tasks: %v", pid, err)
+ }
+ expectedProc := fmt.Sprintf("Pid:\t%d", pid)
+ foundAThread := false
+ for _, f := range fs {
+ tf := fmt.Sprintf("/proc/%s/status", f.Name())
+ d, err := os.ReadFile(tf)
+ if err != nil {
+ // There are a surprising number of ways this
+ // can error out on linux. We've seen all of
+ // the following, so treat any error here as
+ // equivalent to the "process is gone":
+ // os.IsNotExist(err),
+ // "... : no such process",
+ // "... : bad file descriptor.
+ continue
+ }
+ lines := strings.Split(string(d), "\n")
+ for _, line := range lines {
+ // Different kernel vintages pad differently.
+ line = strings.TrimSpace(line)
+ if strings.HasPrefix(line, "Pid:\t") {
+ // On loaded systems, it is possible
+ // for a TID to be reused really
+ // quickly. As such, we need to
+ // validate that the thread status
+ // info we just read is a task of the
+ // same process PID as we are
+ // currently running, and not a
+ // recently terminated thread
+ // resurfaced in a different process.
+ if line != expectedProc {
+ break
+ }
+ // Fall through in the unlikely case
+ // that filter at some point is
+ // "Pid:\t".
+ }
+ if strings.HasPrefix(line, filter) {
+ if line != expected {
+ return fmt.Errorf("%q got:%q want:%q (bad) [pid=%d file:'%s' %v]\n", tf, line, expected, pid, string(d), expectedProc)
+ }
+ foundAThread = true
+ break
+ }
+ }
+ }
+ if !foundAThread {
+ return fmt.Errorf("found no thread /proc/<TID>/status files for process %q", expectedProc)
+ }
+ return nil
+}
+
+// TestSetuidEtc performs tests on all of the wrapped system calls
+// that mirror to the 9 glibc syscalls with POSIX semantics. The test
+// here is considered authoritative and should compile and run
+// CGO_ENABLED=0 or 1. Note, there is an extended copy of this same
+// test in ../../misc/cgo/test/issue1435.go which requires
+// CGO_ENABLED=1 and launches pthreads from C that run concurrently
+// with the Go code of the test - and the test validates that these
+// pthreads are also kept in sync with the security state changed with
+// the syscalls. Care should be taken to mirror any enhancements to
+// this test here in that file too.
+func TestSetuidEtc(t *testing.T) {
+ if syscall.Getuid() != 0 {
+ t.Skip("skipping root only test")
+ }
+ vs := []struct {
+ call string
+ fn func() error
+ filter, expect string
+ }{
+ {call: "Setegid(1)", fn: func() error { return syscall.Setegid(1) }, filter: "Gid:", expect: "\t0\t1\t0\t1"},
+ {call: "Setegid(0)", fn: func() error { return syscall.Setegid(0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
+
+ {call: "Seteuid(1)", fn: func() error { return syscall.Seteuid(1) }, filter: "Uid:", expect: "\t0\t1\t0\t1"},
+ {call: "Setuid(0)", fn: func() error { return syscall.Setuid(0) }, filter: "Uid:", expect: "\t0\t0\t0\t0"},
+
+ {call: "Setgid(1)", fn: func() error { return syscall.Setgid(1) }, filter: "Gid:", expect: "\t1\t1\t1\t1"},
+ {call: "Setgid(0)", fn: func() error { return syscall.Setgid(0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
+
+ {call: "Setgroups([]int{0,1,2,3})", fn: func() error { return syscall.Setgroups([]int{0, 1, 2, 3}) }, filter: "Groups:", expect: "\t0 1 2 3"},
+ {call: "Setgroups(nil)", fn: func() error { return syscall.Setgroups(nil) }, filter: "Groups:", expect: ""},
+ {call: "Setgroups([]int{0})", fn: func() error { return syscall.Setgroups([]int{0}) }, filter: "Groups:", expect: "\t0"},
+
+ {call: "Setregid(101,0)", fn: func() error { return syscall.Setregid(101, 0) }, filter: "Gid:", expect: "\t101\t0\t0\t0"},
+ {call: "Setregid(0,102)", fn: func() error { return syscall.Setregid(0, 102) }, filter: "Gid:", expect: "\t0\t102\t102\t102"},
+ {call: "Setregid(0,0)", fn: func() error { return syscall.Setregid(0, 0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
+
+ {call: "Setreuid(1,0)", fn: func() error { return syscall.Setreuid(1, 0) }, filter: "Uid:", expect: "\t1\t0\t0\t0"},
+ {call: "Setreuid(0,2)", fn: func() error { return syscall.Setreuid(0, 2) }, filter: "Uid:", expect: "\t0\t2\t2\t2"},
+ {call: "Setreuid(0,0)", fn: func() error { return syscall.Setreuid(0, 0) }, filter: "Uid:", expect: "\t0\t0\t0\t0"},
+
+ {call: "Setresgid(101,0,102)", fn: func() error { return syscall.Setresgid(101, 0, 102) }, filter: "Gid:", expect: "\t101\t0\t102\t0"},
+ {call: "Setresgid(0,102,101)", fn: func() error { return syscall.Setresgid(0, 102, 101) }, filter: "Gid:", expect: "\t0\t102\t101\t102"},
+ {call: "Setresgid(0,0,0)", fn: func() error { return syscall.Setresgid(0, 0, 0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
+
+ {call: "Setresuid(1,0,2)", fn: func() error { return syscall.Setresuid(1, 0, 2) }, filter: "Uid:", expect: "\t1\t0\t2\t0"},
+ {call: "Setresuid(0,2,1)", fn: func() error { return syscall.Setresuid(0, 2, 1) }, filter: "Uid:", expect: "\t0\t2\t1\t2"},
+ {call: "Setresuid(0,0,0)", fn: func() error { return syscall.Setresuid(0, 0, 0) }, filter: "Uid:", expect: "\t0\t0\t0\t0"},
+ }
+
+ for i, v := range vs {
+ if err := v.fn(); err != nil {
+ t.Errorf("[%d] %q failed: %v", i, v.call, err)
+ continue
+ }
+ if err := compareStatus(v.filter, v.expect); err != nil {
+ t.Errorf("[%d] %q comparison: %v", i, v.call, err)
+ }
+ }
+}
diff --git a/libgo/go/syscall/syscall_unix.go b/libgo/go/syscall/syscall_unix.go
index 4d963fb..db6b3aa 100644
--- a/libgo/go/syscall/syscall_unix.go
+++ b/libgo/go/syscall/syscall_unix.go
@@ -21,7 +21,7 @@ var (
)
const (
- darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
+ darwin64Bit = (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && sizeofPtr == 8
netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
)
diff --git a/libgo/go/syscall/syscall_unix_test.go b/libgo/go/syscall/syscall_unix_test.go
index a6b70d4..e4b4171 100644
--- a/libgo/go/syscall/syscall_unix_test.go
+++ b/libgo/go/syscall/syscall_unix_test.go
@@ -11,7 +11,6 @@ import (
"fmt"
"internal/testenv"
"io"
- "io/ioutil"
"net"
"os"
"os/exec"
@@ -72,7 +71,7 @@ func _() {
// Thus this test also verifies that the Flock_t structure can be
// roundtripped with F_SETLK and F_GETLK.
func TestFcntlFlock(t *testing.T) {
- if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
+ if runtime.GOOS == "ios" {
t.Skip("skipping; no child processes allowed on iOS")
}
flock := syscall.Flock_t{
@@ -81,7 +80,7 @@ func TestFcntlFlock(t *testing.T) {
}
if os.Getenv("GO_WANT_HELPER_PROCESS") == "" {
// parent
- tempDir, err := ioutil.TempDir("", "TestFcntlFlock")
+ tempDir, err := os.MkdirTemp("", "TestFcntlFlock")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
@@ -159,7 +158,7 @@ func TestPassFD(t *testing.T) {
}
- tempDir, err := ioutil.TempDir("", "TestPassFD")
+ tempDir, err := os.MkdirTemp("", "TestPassFD")
if err != nil {
t.Fatal(err)
}
@@ -227,7 +226,7 @@ func TestPassFD(t *testing.T) {
f := os.NewFile(uintptr(gotFds[0]), "fd-from-child")
defer f.Close()
- got, err := ioutil.ReadAll(f)
+ got, err := io.ReadAll(f)
want := "Hello from child process!\n"
if string(got) != want {
t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want)
@@ -259,7 +258,7 @@ func passFDChild() {
// We make it in tempDir, which our parent will clean up.
flag.Parse()
tempDir := flag.Arg(0)
- f, err := ioutil.TempFile(tempDir, "")
+ f, err := os.CreateTemp(tempDir, "")
if err != nil {
fmt.Printf("TempFile: %v", err)
return
@@ -338,11 +337,11 @@ func TestRlimit(t *testing.T) {
}
set := rlimit
set.Cur = set.Max - 1
- if runtime.GOOS == "darwin" && set.Cur > 10240 {
- // The max file limit is 10240, even though
- // the max returned by Getrlimit is 1<<63-1.
- // This is OPEN_MAX in sys/syslimits.h.
- set.Cur = 10240
+ if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && set.Cur > 4096 {
+ // rlim_min for RLIMIT_NOFILE should be equal to
+ // or lower than kern.maxfilesperproc, which on
+ // some machines are 4096. See #40564.
+ set.Cur = 4096
}
err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &set)
if err != nil {
@@ -355,8 +354,8 @@ func TestRlimit(t *testing.T) {
}
set = rlimit
set.Cur = set.Max - 1
- if runtime.GOOS == "darwin" && set.Cur > 10240 {
- set.Cur = 10240
+ if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && set.Cur > 4096 {
+ set.Cur = 4096
}
if set != get {
t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get)
diff --git a/libgo/go/syscall/timestruct.go b/libgo/go/syscall/timestruct.go
index bd0b3de..42a743e 100644
--- a/libgo/go/syscall/timestruct.go
+++ b/libgo/go/syscall/timestruct.go
@@ -6,12 +6,10 @@
package syscall
-// TimespecToNsec converts a Timespec value into a number of
-// nanoseconds since the Unix epoch.
+// TimespecToNSec returns the time stored in ts as nanoseconds.
func TimespecToNsec(ts Timespec) int64 { return ts.Nano() }
-// NsecToTimespec takes a number of nanoseconds since the Unix epoch
-// and returns the corresponding Timespec value.
+// NsecToTimespec converts a number of nanoseconds into a Timespec.
func NsecToTimespec(nsec int64) Timespec {
sec := nsec / 1e9
nsec = nsec % 1e9
@@ -22,12 +20,10 @@ func NsecToTimespec(nsec int64) Timespec {
return setTimespec(sec, nsec)
}
-// TimevalToNsec converts a Timeval value into a number of nanoseconds
-// since the Unix epoch.
+// TimevalToNsec returns the time stored in tv as nanoseconds.
func TimevalToNsec(tv Timeval) int64 { return tv.Nano() }
-// NsecToTimeval takes a number of nanoseconds since the Unix epoch
-// and returns the corresponding Timeval value.
+// NsecToTimeval converts a number of nanoseconds into a Timeval.
func NsecToTimeval(nsec int64) Timeval {
nsec += 999 // round up to microsecond
usec := nsec % 1e9 / 1e3