Fix "PR c++/92804 ICE trying to use concept as a nested-name-specifier"
[official-gcc.git] / libgo / go / syscall / syscall_linux_test.go
blob97059c87d3dd4b708c0d056dd6057d43ccdf9864
1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 package syscall_test
7 import (
8 "bufio"
9 "fmt"
10 "io"
11 "io/ioutil"
12 "os"
13 "os/exec"
14 "os/signal"
15 "path/filepath"
16 "runtime"
17 "strconv"
18 "strings"
19 "syscall"
20 "testing"
21 "time"
22 "unsafe"
25 // chtmpdir changes the working directory to a new temporary directory and
26 // provides a cleanup function. Used when PWD is read-only.
27 func chtmpdir(t *testing.T) func() {
28 oldwd, err := os.Getwd()
29 if err != nil {
30 t.Fatalf("chtmpdir: %v", err)
32 d, err := ioutil.TempDir("", "test")
33 if err != nil {
34 t.Fatalf("chtmpdir: %v", err)
36 if err := os.Chdir(d); err != nil {
37 t.Fatalf("chtmpdir: %v", err)
39 return func() {
40 if err := os.Chdir(oldwd); err != nil {
41 t.Fatalf("chtmpdir: %v", err)
43 os.RemoveAll(d)
47 func touch(t *testing.T, name string) {
48 f, err := os.Create(name)
49 if err != nil {
50 t.Fatal(err)
52 if err := f.Close(); err != nil {
53 t.Fatal(err)
57 const (
58 _AT_SYMLINK_NOFOLLOW = 0x100
59 _AT_FDCWD = -0x64
60 _AT_EACCESS = 0x200
61 _F_OK = 0
62 _R_OK = 4
65 func TestFaccessat(t *testing.T) {
66 defer chtmpdir(t)()
67 touch(t, "file1")
69 err := syscall.Faccessat(_AT_FDCWD, "file1", _R_OK, 0)
70 if err != nil {
71 t.Errorf("Faccessat: unexpected error: %v", err)
74 err = syscall.Faccessat(_AT_FDCWD, "file1", _R_OK, 2)
75 if err != syscall.EINVAL {
76 t.Errorf("Faccessat: unexpected error: %v, want EINVAL", err)
79 err = syscall.Faccessat(_AT_FDCWD, "file1", _R_OK, _AT_EACCESS)
80 if err != nil {
81 t.Errorf("Faccessat: unexpected error: %v", err)
84 err = os.Symlink("file1", "symlink1")
85 if err != nil {
86 t.Fatal(err)
89 err = syscall.Faccessat(_AT_FDCWD, "symlink1", _R_OK, _AT_SYMLINK_NOFOLLOW)
90 if err != nil {
91 t.Errorf("Faccessat SYMLINK_NOFOLLOW: unexpected error %v", err)
94 // We can't really test _AT_SYMLINK_NOFOLLOW, because there
95 // doesn't seem to be any way to change the mode of a symlink.
96 // We don't test _AT_EACCESS because such tests are only
97 // meaningful if run as root.
99 err = syscall.Fchmodat(_AT_FDCWD, "file1", 0, 0)
100 if err != nil {
101 t.Errorf("Fchmodat: unexpected error %v", err)
104 err = syscall.Faccessat(_AT_FDCWD, "file1", _F_OK, _AT_SYMLINK_NOFOLLOW)
105 if err != nil {
106 t.Errorf("Faccessat: unexpected error: %v", err)
109 err = syscall.Faccessat(_AT_FDCWD, "file1", _R_OK, _AT_SYMLINK_NOFOLLOW)
110 if err != syscall.EACCES {
111 if syscall.Getuid() != 0 {
112 t.Errorf("Faccessat: unexpected error: %v, want EACCES", err)
117 func TestFchmodat(t *testing.T) {
118 defer chtmpdir(t)()
120 touch(t, "file1")
121 os.Symlink("file1", "symlink1")
123 err := syscall.Fchmodat(_AT_FDCWD, "symlink1", 0444, 0)
124 if err != nil {
125 t.Fatalf("Fchmodat: unexpected error: %v", err)
128 fi, err := os.Stat("file1")
129 if err != nil {
130 t.Fatal(err)
133 if fi.Mode() != 0444 {
134 t.Errorf("Fchmodat: failed to change mode: expected %v, got %v", 0444, fi.Mode())
137 err = syscall.Fchmodat(_AT_FDCWD, "symlink1", 0444, _AT_SYMLINK_NOFOLLOW)
138 if err != syscall.EOPNOTSUPP {
139 t.Fatalf("Fchmodat: unexpected error: %v, expected EOPNOTSUPP", err)
143 func TestMain(m *testing.M) {
144 if os.Getenv("GO_DEATHSIG_PARENT") == "1" {
145 deathSignalParent()
146 } else if os.Getenv("GO_DEATHSIG_CHILD") == "1" {
147 deathSignalChild()
148 } else if os.Getenv("GO_SYSCALL_NOERROR") == "1" {
149 syscallNoError()
152 os.Exit(m.Run())
155 func TestLinuxDeathSignal(t *testing.T) {
156 if os.Getuid() != 0 {
157 t.Skip("skipping root only test")
160 // Copy the test binary to a location that a non-root user can read/execute
161 // after we drop privileges
162 tempDir, err := ioutil.TempDir("", "TestDeathSignal")
163 if err != nil {
164 t.Fatalf("cannot create temporary directory: %v", err)
166 defer os.RemoveAll(tempDir)
167 os.Chmod(tempDir, 0755)
169 tmpBinary := filepath.Join(tempDir, filepath.Base(os.Args[0]))
171 src, err := os.Open(os.Args[0])
172 if err != nil {
173 t.Fatalf("cannot open binary %q, %v", os.Args[0], err)
175 defer src.Close()
177 dst, err := os.OpenFile(tmpBinary, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
178 if err != nil {
179 t.Fatalf("cannot create temporary binary %q, %v", tmpBinary, err)
181 if _, err := io.Copy(dst, src); err != nil {
182 t.Fatalf("failed to copy test binary to %q, %v", tmpBinary, err)
184 err = dst.Close()
185 if err != nil {
186 t.Fatalf("failed to close test binary %q, %v", tmpBinary, err)
189 cmd := exec.Command(tmpBinary)
190 cmd.Env = []string{"GO_DEATHSIG_PARENT=1"}
191 chldStdin, err := cmd.StdinPipe()
192 if err != nil {
193 t.Fatalf("failed to create new stdin pipe: %v", err)
195 chldStdout, err := cmd.StdoutPipe()
196 if err != nil {
197 t.Fatalf("failed to create new stdout pipe: %v", err)
199 cmd.Stderr = os.Stderr
201 err = cmd.Start()
202 defer cmd.Wait()
203 if err != nil {
204 t.Fatalf("failed to start first child process: %v", err)
207 chldPipe := bufio.NewReader(chldStdout)
209 if got, err := chldPipe.ReadString('\n'); got == "start\n" {
210 syscall.Kill(cmd.Process.Pid, syscall.SIGTERM)
212 go func() {
213 time.Sleep(5 * time.Second)
214 chldStdin.Close()
217 want := "ok\n"
218 if got, err = chldPipe.ReadString('\n'); got != want {
219 t.Fatalf("expected %q, received %q, %v", want, got, err)
221 } else {
222 t.Fatalf("did not receive start from child, received %q, %v", got, err)
226 func deathSignalParent() {
227 cmd := exec.Command(os.Args[0])
228 cmd.Env = []string{"GO_DEATHSIG_CHILD=1"}
229 cmd.Stdin = os.Stdin
230 cmd.Stdout = os.Stdout
231 attrs := syscall.SysProcAttr{
232 Pdeathsig: syscall.SIGUSR1,
233 // UID/GID 99 is the user/group "nobody" on RHEL/Fedora and is
234 // unused on Ubuntu
235 Credential: &syscall.Credential{Uid: 99, Gid: 99},
237 cmd.SysProcAttr = &attrs
239 err := cmd.Start()
240 if err != nil {
241 fmt.Fprintf(os.Stderr, "death signal parent error: %v\n", err)
242 os.Exit(1)
244 cmd.Wait()
245 os.Exit(0)
248 func deathSignalChild() {
249 c := make(chan os.Signal, 1)
250 signal.Notify(c, syscall.SIGUSR1)
251 go func() {
253 fmt.Println("ok")
254 os.Exit(0)
256 fmt.Println("start")
258 buf := make([]byte, 32)
259 os.Stdin.Read(buf)
261 // We expected to be signaled before stdin closed
262 fmt.Println("not ok")
263 os.Exit(1)
266 func TestParseNetlinkMessage(t *testing.T) {
267 for i, b := range [][]byte{
268 {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,
269 0, 8, 0, 6, 0, 0, 0, 0, 1, 63, 0, 10, 0, 69, 16, 0, 59, 39, 82, 64, 0, 64, 6, 21, 89, 127, 0, 0,
270 1, 127, 0, 0, 1, 230, 228, 31, 144, 32, 186, 155, 211, 185, 151, 209, 179, 128, 24, 1, 86,
271 53, 119, 0, 0, 1, 1, 8, 10, 0, 17, 234, 12, 0, 17, 189, 126, 107, 106, 108, 107, 106, 13, 10,
273 {106, 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, 3, 8, 0, 3,
274 0, 8, 0, 6, 0, 0, 0, 0, 1, 66, 0, 10, 0, 69, 0, 0, 62, 230, 255, 64, 0, 64, 6, 85, 184, 127, 0, 0,
275 1, 127, 0, 0, 1, 237, 206, 31, 144, 73, 197, 128, 65, 250, 60, 192, 97, 128, 24, 1, 86, 253, 21, 0,
276 0, 1, 1, 8, 10, 0, 51, 106, 89, 0, 51, 102, 198, 108, 104, 106, 108, 107, 104, 108, 107, 104, 10,
278 {102, 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, 1, 8, 0, 3, 0,
279 8, 0, 6, 0, 0, 0, 0, 1, 62, 0, 10, 0, 69, 0, 0, 58, 231, 2, 64, 0, 64, 6, 85, 185, 127, 0, 0, 1, 127,
280 0, 0, 1, 237, 206, 31, 144, 73, 197, 128, 86, 250, 60, 192, 97, 128, 24, 1, 86, 104, 64, 0, 0, 1, 1, 8,
281 10, 0, 52, 198, 200, 0, 51, 135, 232, 101, 115, 97, 103, 103, 10,
284 m, err := syscall.ParseNetlinkMessage(b)
285 if err != syscall.EINVAL {
286 t.Errorf("#%d: got %v; want EINVAL", i, err)
288 if m != nil {
289 t.Errorf("#%d: got %v; want nil", i, m)
294 func TestSyscallNoError(t *testing.T) {
295 // On Linux there are currently no syscalls which don't fail and return
296 // a value larger than 0xfffffffffffff001 so we could test RawSyscall
297 // vs. RawSyscallNoError on 64bit architectures.
298 if unsafe.Sizeof(uintptr(0)) != 4 {
299 t.Skip("skipping on non-32bit architecture")
302 // See https://golang.org/issue/35422
303 // On MIPS, Linux returns whether the syscall had an error in a separate
304 // register (R7), not using a negative return value as on other
305 // architectures.
306 if runtime.GOARCH == "mips" || runtime.GOARCH == "mipsle" {
307 t.Skipf("skipping on %s", runtime.GOARCH)
310 if os.Getuid() != 0 {
311 t.Skip("skipping root only test")
314 if syscall.Sys_GETEUID == 0 {
315 t.Skip("skipping because there is no geteuid system call")
318 if runtime.GOOS == "android" {
319 t.Skip("skipping on rooted android, see issue 27364")
322 // Copy the test binary to a location that a non-root user can read/execute
323 // after we drop privileges
324 tempDir, err := ioutil.TempDir("", "TestSyscallNoError")
325 if err != nil {
326 t.Fatalf("cannot create temporary directory: %v", err)
328 defer os.RemoveAll(tempDir)
329 os.Chmod(tempDir, 0755)
331 tmpBinary := filepath.Join(tempDir, filepath.Base(os.Args[0]))
333 src, err := os.Open(os.Args[0])
334 if err != nil {
335 t.Fatalf("cannot open binary %q, %v", os.Args[0], err)
337 defer src.Close()
339 dst, err := os.OpenFile(tmpBinary, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
340 if err != nil {
341 t.Fatalf("cannot create temporary binary %q, %v", tmpBinary, err)
343 if _, err := io.Copy(dst, src); err != nil {
344 t.Fatalf("failed to copy test binary to %q, %v", tmpBinary, err)
346 err = dst.Close()
347 if err != nil {
348 t.Fatalf("failed to close test binary %q, %v", tmpBinary, err)
351 uid := uint32(0xfffffffe)
352 err = os.Chown(tmpBinary, int(uid), -1)
353 if err != nil {
354 t.Fatalf("failed to chown test binary %q, %v", tmpBinary, err)
357 err = os.Chmod(tmpBinary, 0755|os.ModeSetuid)
358 if err != nil {
359 t.Fatalf("failed to set setuid bit on test binary %q, %v", tmpBinary, err)
362 cmd := exec.Command(tmpBinary)
363 cmd.Env = []string{"GO_SYSCALL_NOERROR=1"}
365 out, err := cmd.CombinedOutput()
366 if err != nil {
367 t.Fatalf("failed to start first child process: %v", err)
370 got := strings.TrimSpace(string(out))
371 want := strconv.FormatUint(uint64(uid)+1, 10) + " / " +
372 strconv.FormatUint(uint64(-uid), 10) + " / " +
373 strconv.FormatUint(uint64(uid), 10)
374 if got != want {
375 if filesystemIsNoSUID(tmpBinary) {
376 t.Skip("skipping test when temp dir is mounted nosuid")
378 // formatted so the values are aligned for easier comparison
379 t.Errorf("expected %s,\ngot %s", want, got)
383 // filesystemIsNoSUID reports whether the filesystem for the given
384 // path is mounted nosuid.
385 func filesystemIsNoSUID(path string) bool {
386 var st syscall.Statfs_t
387 if syscall.Statfs(path, &st) != nil {
388 return false
390 return st.Flags&syscall.MS_NOSUID != 0
393 func syscallNoError() {
394 // Test that the return value from SYS_GETEUID32 (which cannot fail)
395 // doesn't get treated as an error (see https://golang.org/issue/22924)
396 euid1, _, e := syscall.RawSyscall(syscall.Sys_GETEUID, 0, 0, 0)
397 euid2, _ := syscall.RawSyscallNoError(syscall.Sys_GETEUID, 0, 0, 0)
399 fmt.Println(uintptr(euid1), "/", int(e), "/", uintptr(euid2))
400 os.Exit(0)