]> Cypherpunks repositories - gostls13.git/commitdiff
syscall: handle undefined r2 value on linux-ppc64x
authorAndrew G. Morgan <agm@google.com>
Wed, 28 Oct 2020 20:35:57 +0000 (13:35 -0700)
committerIan Lance Taylor <iant@golang.org>
Thu, 29 Oct 2020 17:53:57 +0000 (17:53 +0000)
This change fixes two failng tests on linux-ppc64x:

- TestAllThreadsSyscall() exposed a real bug in the ppc64x support:
  - It turns out that the r2 syscall return value is not defined
    on all architectures. Notably linux-ppc64x so address that by
    introducing a private architectural constant in the syscall
    package, archHonorsR2: true if r2 has a determanistic value.

- TestSetuidEtc() was sensitive to /proc/<PID>/status content:
  - The amount of padding space has changed with kernel vintage.
  - Stress testing revealed a race with /proc files disappearing.

Fixes #42178

Change-Id: Ie6fc0b8f2f94a409ac0e5756e73bfce113274709
Reviewed-on: https://go-review.googlesource.com/c/go/+/266202
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>

src/syscall/syscall_linux.go
src/syscall/syscall_linux_386.go
src/syscall/syscall_linux_amd64.go
src/syscall/syscall_linux_arm.go
src/syscall/syscall_linux_arm64.go
src/syscall/syscall_linux_mips64x.go
src/syscall/syscall_linux_mipsx.go
src/syscall/syscall_linux_ppc64x.go
src/syscall/syscall_linux_riscv64.go
src/syscall/syscall_linux_s390x.go
src/syscall/syscall_linux_test.go

index 54e5cfc2f26c45e4cc13a44145a0ff855da26cb7..3041f6f8fceda79c0fe34474617361c0d126d8b7 100644 (file)
@@ -1003,7 +1003,9 @@ func (pc *allThreadsCaller) doSyscall(initial bool) bool {
                pc.r1 = r1
                pc.r2 = r2
                pc.err = err
-       } else if pc.r1 != r1 || pc.r2 != r2 || pc.err != err {
+       } else if pc.r1 != r1 || (archHonorsR2 && pc.r2 != r2) || pc.err != err {
+               print("trap:", pc.trap, ", a123=[", pc.a1, ",", pc.a2, ",", pc.a3, "]\n")
+               print("results: got {r1=", r1, ",r2=", r2, ",err=", err, "}, want {r1=", pc.r1, ",r2=", pc.r2, ",r3=", pc.err, "}\n")
                panic("AllThreadsSyscall results differ between threads; runtime corrupted")
        }
        return err == 0
@@ -1019,7 +1021,9 @@ func (pc *allThreadsCaller) doSyscall6(initial bool) bool {
                pc.r1 = r1
                pc.r2 = r2
                pc.err = err
-       } else if pc.r1 != r1 || pc.r2 != r2 || pc.err != err {
+       } else if pc.r1 != r1 || (archHonorsR2 && pc.r2 != r2) || pc.err != err {
+               print("trap:", pc.trap, ", a123456=[", pc.a1, ",", pc.a2, ",", pc.a3, ",", pc.a4, ",", pc.a5, ",", pc.a6, "]\n")
+               print("results: got {r1=", r1, ",r2=", r2, ",err=", err, "}, want {r1=", pc.r1, ",r2=", pc.r2, ",r3=", pc.err, "}\n")
                panic("AllThreadsSyscall6 results differ between threads; runtime corrupted")
        }
        return err == 0
index dd5f2735d81baf6ed4f35255149945af45b39303..ed5264740346bad129dc8feaeb7fcc15fb2650d8 100644 (file)
@@ -6,6 +6,12 @@ package syscall
 
 import "unsafe"
 
+// archHonorsR2 captures the fact that r2 is honored by the
+// runtime.GOARCH.  Syscall conventions are generally r1, r2, err :=
+// syscall(trap, ...).  Not all architectures define r2 in their
+// ABI. See "man syscall".
+const archHonorsR2 = true
+
 const _SYS_setgroups = SYS_SETGROUPS32
 
 func setTimespec(sec, nsec int64) Timespec {
index 5518f44a074028b93c4498fc0f7a40d2e4a9d514..5df3f796d1677785114bad853ae8479e8fee83b6 100644 (file)
@@ -4,6 +4,12 @@
 
 package syscall
 
+// archHonorsR2 captures the fact that r2 is honored by the
+// runtime.GOARCH.  Syscall conventions are generally r1, r2, err :=
+// syscall(trap, ...).  Not all architectures define r2 in their
+// ABI. See "man syscall".
+const archHonorsR2 = true
+
 const _SYS_setgroups = SYS_SETGROUPS
 
 //sys  Dup2(oldfd int, newfd int) (err error)
index 61133a59fb0686742abf631a83ffca7d5c751932..4a3729f8981b520df330b24674abc1e61b8b1948 100644 (file)
@@ -6,6 +6,12 @@ package syscall
 
 import "unsafe"
 
+// archHonorsR2 captures the fact that r2 is honored by the
+// runtime.GOARCH.  Syscall conventions are generally r1, r2, err :=
+// syscall(trap, ...).  Not all architectures define r2 in their
+// ABI. See "man syscall". [EABI assumed.]
+const archHonorsR2 = true
+
 const _SYS_setgroups = SYS_SETGROUPS32
 
 func setTimespec(sec, nsec int64) Timespec {
index 16382102c89f0c799556b00e922b1f45689c4d77..f575c84c930c2d0a884893289a285a939a0b4b07 100644 (file)
@@ -6,6 +6,12 @@ package syscall
 
 import "unsafe"
 
+// archHonorsR2 captures the fact that r2 is honored by the
+// runtime.GOARCH.  Syscall conventions are generally r1, r2, err :=
+// syscall(trap, ...).  Not all architectures define r2 in their
+// ABI. See "man syscall".
+const archHonorsR2 = true
+
 const _SYS_setgroups = SYS_SETGROUPS
 
 func EpollCreate(size int) (fd int, err error) {
index 4986baa31980d8078fcd5d28bdbc142ee8d18990..ab25b7be6f1313579973f7d6493239cd1dbd52b0 100644 (file)
@@ -7,6 +7,12 @@
 
 package syscall
 
+// archHonorsR2 captures the fact that r2 is honored by the
+// runtime.GOARCH.  Syscall conventions are generally r1, r2, err :=
+// syscall(trap, ...).  Not all architectures define r2 in their
+// ABI. See "man syscall".
+const archHonorsR2 = true
+
 const _SYS_setgroups = SYS_SETGROUPS
 
 //sys  Dup2(oldfd int, newfd int) (err error)
index 5126b0e43cb3361c631d2cb12f93c115e8eb814d..377946fc92dd0b7103839228c4d5661fc47d6371 100644 (file)
@@ -9,6 +9,12 @@ package syscall
 
 import "unsafe"
 
+// archHonorsR2 captures the fact that r2 is honored by the
+// runtime.GOARCH.  Syscall conventions are generally r1, r2, err :=
+// syscall(trap, ...).  Not all architectures define r2 in their
+// ABI. See "man syscall".
+const archHonorsR2 = true
+
 const _SYS_setgroups = SYS_SETGROUPS
 
 func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
index bb2d904b5fb61f3648dbc3900cddfc69240f182e..45bf667407fef8782045a2a1fc0087c69a47fb3e 100644 (file)
@@ -7,6 +7,12 @@
 
 package syscall
 
+// archHonorsR2 captures the fact that r2 is honored by the
+// runtime.GOARCH.  Syscall conventions are generally r1, r2, err :=
+// syscall(trap, ...).  Not all architectures define r2 in their
+// ABI. See "man syscall".
+const archHonorsR2 = false
+
 const _SYS_setgroups = SYS_SETGROUPS
 
 //sys  Dup2(oldfd int, newfd int) (err error)
index aa1014f8aeeff1552516cbd3c9fdce80662c8f15..2a0fe64d258617a8dc147d17d55cc8d205e0905b 100644 (file)
@@ -6,6 +6,12 @@ package syscall
 
 import "unsafe"
 
+// archHonorsR2 captures the fact that r2 is honored by the
+// runtime.GOARCH.  Syscall conventions are generally r1, r2, err :=
+// syscall(trap, ...).  Not all architectures define r2 in their
+// ABI. See "man syscall".
+const archHonorsR2 = true
+
 const _SYS_setgroups = SYS_SETGROUPS
 
 func EpollCreate(size int) (fd int, err error) {
index dc97d5c65acb61c05a6dd03642e32ed0f26c8753..0f6f6277bbfda2b02aab58268b77ce9b796c2097 100644 (file)
@@ -6,6 +6,12 @@ package syscall
 
 import "unsafe"
 
+// archHonorsR2 captures the fact that r2 is honored by the
+// runtime.GOARCH.  Syscall conventions are generally r1, r2, err :=
+// syscall(trap, ...).  Not all architectures define r2 in their
+// ABI. See "man syscall".
+const archHonorsR2 = true
+
 const _SYS_setgroups = SYS_SETGROUPS
 
 //sys  Dup2(oldfd int, newfd int) (err error)
index 0742ef5b077bf778e36a6a27cd4192f6651ac758..41ae8cc5a1e40ecf87527da24269b021e6f3c398 100644 (file)
@@ -410,9 +410,6 @@ const (
 // syscalls that execute on all OSThreads - with which to support
 // POSIX semantics for security state changes.
 func TestAllThreadsSyscall(t *testing.T) {
-       if runtime.GOARCH == "ppc64" {
-               t.Skip("skipping on linux/ppc64; see issue #42178")
-       }
        if _, _, err := syscall.AllThreadsSyscall(syscall.SYS_PRCTL, PR_SET_KEEPCAPS, 0, 0); err == syscall.ENOTSUP {
                t.Skip("AllThreadsSyscall disabled with cgo")
        }
@@ -544,7 +541,7 @@ func TestAllThreadsSyscall(t *testing.T) {
 // compareStatus is used to confirm the contents of the thread
 // specific status files match expectations.
 func compareStatus(filter, expect string) error {
-       expected := filter + "\t" + expect
+       expected := filter + expect
        pid := syscall.Getpid()
        fs, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/task", pid))
        if err != nil {
@@ -553,14 +550,22 @@ func compareStatus(filter, expect string) error {
        for _, f := range fs {
                tf := fmt.Sprintf("/proc/%s/status", f.Name())
                d, err := ioutil.ReadFile(tf)
+               if os.IsNotExist(err) {
+                       // We are racing against threads dying, which
+                       // is out of our control, so ignore the
+                       // missing file and skip to the next one.
+                       continue
+               }
                if err != nil {
                        return fmt.Errorf("unable to read %q: %v", tf, err)
                }
                lines := strings.Split(string(d), "\n")
                for _, line := range lines {
+                       // Different kernel vintages pad differently.
+                       line = strings.TrimSpace(line)
                        if strings.HasPrefix(line, filter) {
                                if line != expected {
-                                       return fmt.Errorf("%s %s (bad)\n", tf, line)
+                                       return fmt.Errorf("%q got:%q want:%q (bad)\n", tf, line, expected)
                                }
                                break
                        }
@@ -580,9 +585,6 @@ func compareStatus(filter, expect string) error {
 // the syscalls. Care should be taken to mirror any enhancements to
 // this test here in that file too.
 func TestSetuidEtc(t *testing.T) {
-       if runtime.GOARCH == "ppc64" {
-               t.Skip("skipping on linux/ppc64; see issue #42178")
-       }
        if syscall.Getuid() != 0 {
                t.Skip("skipping root only test")
        }
@@ -591,34 +593,34 @@ func TestSetuidEtc(t *testing.T) {
                fn             func() error
                filter, expect string
        }{
-               {call: "Setegid(1)", fn: func() error { return syscall.Setegid(1) }, filter: "Gid:", expect: "0\t1\t0\t1"},
-               {call: "Setegid(0)", fn: func() error { return syscall.Setegid(0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
+               {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: "0\t1\t0\t1"},
-               {call: "Setuid(0)", fn: func() error { return syscall.Setuid(0) }, filter: "Uid:", expect: "0\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: "1\t1\t1\t1"},
-               {call: "Setgid(0)", fn: func() error { return syscall.Setgid(0) }, filter: "Gid:", expect: "0\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: "0 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: ""},
+               {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: "101\t0\t0\t0"},
-               {call: "Setregid(0,102)", fn: func() error { return syscall.Setregid(0, 102) }, filter: "Gid:", expect: "0\t102\t102\t102"},
-               {call: "Setregid(0,0)", fn: func() error { return syscall.Setregid(0, 0) }, filter: "Gid:", expect: "0\t0\t0\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: "1\t0\t0\t0"},
-               {call: "Setreuid(0,2)", fn: func() error { return syscall.Setreuid(0, 2) }, filter: "Uid:", expect: "0\t2\t2\t2"},
-               {call: "Setreuid(0,0)", fn: func() error { return syscall.Setreuid(0, 0) }, filter: "Uid:", expect: "0\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: "101\t0\t102\t0"},
-               {call: "Setresgid(0,102,101)", fn: func() error { return syscall.Setresgid(0, 102, 101) }, filter: "Gid:", expect: "0\t102\t101\t102"},
-               {call: "Setresgid(0,0,0)", fn: func() error { return syscall.Setresgid(0, 0, 0) }, filter: "Gid:", expect: "0\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: "1\t0\t2\t0"},
-               {call: "Setresuid(0,2,1)", fn: func() error { return syscall.Setresuid(0, 2, 1) }, filter: "Uid:", expect: "0\t2\t1\t2"},
-               {call: "Setresuid(0,0,0)", fn: func() error { return syscall.Setresuid(0, 0, 0) }, filter: "Uid:", expect: "0\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 {