Skip to content

Commit 3a819e8

Browse files
AndrewGMorganianlancetaylor
authored andcommitted
syscall: handle undefined r2 value on linux-ppc64x
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 <[email protected]> Reviewed-by: Emmanuel Odeke <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> TryBot-Result: Go Bot <[email protected]>
1 parent 4fb4291 commit 3a819e8

11 files changed

+91
-31
lines changed

src/syscall/syscall_linux.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,7 +1003,9 @@ func (pc *allThreadsCaller) doSyscall(initial bool) bool {
10031003
pc.r1 = r1
10041004
pc.r2 = r2
10051005
pc.err = err
1006-
} else if pc.r1 != r1 || pc.r2 != r2 || pc.err != err {
1006+
} else if pc.r1 != r1 || (archHonorsR2 && pc.r2 != r2) || pc.err != err {
1007+
print("trap:", pc.trap, ", a123=[", pc.a1, ",", pc.a2, ",", pc.a3, "]\n")
1008+
print("results: got {r1=", r1, ",r2=", r2, ",err=", err, "}, want {r1=", pc.r1, ",r2=", pc.r2, ",r3=", pc.err, "}\n")
10071009
panic("AllThreadsSyscall results differ between threads; runtime corrupted")
10081010
}
10091011
return err == 0
@@ -1019,7 +1021,9 @@ func (pc *allThreadsCaller) doSyscall6(initial bool) bool {
10191021
pc.r1 = r1
10201022
pc.r2 = r2
10211023
pc.err = err
1022-
} else if pc.r1 != r1 || pc.r2 != r2 || pc.err != err {
1024+
} else if pc.r1 != r1 || (archHonorsR2 && pc.r2 != r2) || pc.err != err {
1025+
print("trap:", pc.trap, ", a123456=[", pc.a1, ",", pc.a2, ",", pc.a3, ",", pc.a4, ",", pc.a5, ",", pc.a6, "]\n")
1026+
print("results: got {r1=", r1, ",r2=", r2, ",err=", err, "}, want {r1=", pc.r1, ",r2=", pc.r2, ",r3=", pc.err, "}\n")
10231027
panic("AllThreadsSyscall6 results differ between threads; runtime corrupted")
10241028
}
10251029
return err == 0

src/syscall/syscall_linux_386.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ package syscall
66

77
import "unsafe"
88

9+
// archHonorsR2 captures the fact that r2 is honored by the
10+
// runtime.GOARCH. Syscall conventions are generally r1, r2, err :=
11+
// syscall(trap, ...). Not all architectures define r2 in their
12+
// ABI. See "man syscall".
13+
const archHonorsR2 = true
14+
915
const _SYS_setgroups = SYS_SETGROUPS32
1016

1117
func setTimespec(sec, nsec int64) Timespec {

src/syscall/syscall_linux_amd64.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44

55
package syscall
66

7+
// archHonorsR2 captures the fact that r2 is honored by the
8+
// runtime.GOARCH. Syscall conventions are generally r1, r2, err :=
9+
// syscall(trap, ...). Not all architectures define r2 in their
10+
// ABI. See "man syscall".
11+
const archHonorsR2 = true
12+
713
const _SYS_setgroups = SYS_SETGROUPS
814

915
//sys Dup2(oldfd int, newfd int) (err error)

src/syscall/syscall_linux_arm.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ package syscall
66

77
import "unsafe"
88

9+
// archHonorsR2 captures the fact that r2 is honored by the
10+
// runtime.GOARCH. Syscall conventions are generally r1, r2, err :=
11+
// syscall(trap, ...). Not all architectures define r2 in their
12+
// ABI. See "man syscall". [EABI assumed.]
13+
const archHonorsR2 = true
14+
915
const _SYS_setgroups = SYS_SETGROUPS32
1016

1117
func setTimespec(sec, nsec int64) Timespec {

src/syscall/syscall_linux_arm64.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ package syscall
66

77
import "unsafe"
88

9+
// archHonorsR2 captures the fact that r2 is honored by the
10+
// runtime.GOARCH. Syscall conventions are generally r1, r2, err :=
11+
// syscall(trap, ...). Not all architectures define r2 in their
12+
// ABI. See "man syscall".
13+
const archHonorsR2 = true
14+
915
const _SYS_setgroups = SYS_SETGROUPS
1016

1117
func EpollCreate(size int) (fd int, err error) {

src/syscall/syscall_linux_mips64x.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77

88
package syscall
99

10+
// archHonorsR2 captures the fact that r2 is honored by the
11+
// runtime.GOARCH. Syscall conventions are generally r1, r2, err :=
12+
// syscall(trap, ...). Not all architectures define r2 in their
13+
// ABI. See "man syscall".
14+
const archHonorsR2 = true
15+
1016
const _SYS_setgroups = SYS_SETGROUPS
1117

1218
//sys Dup2(oldfd int, newfd int) (err error)

src/syscall/syscall_linux_mipsx.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ package syscall
99

1010
import "unsafe"
1111

12+
// archHonorsR2 captures the fact that r2 is honored by the
13+
// runtime.GOARCH. Syscall conventions are generally r1, r2, err :=
14+
// syscall(trap, ...). Not all architectures define r2 in their
15+
// ABI. See "man syscall".
16+
const archHonorsR2 = true
17+
1218
const _SYS_setgroups = SYS_SETGROUPS
1319

1420
func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)

src/syscall/syscall_linux_ppc64x.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77

88
package syscall
99

10+
// archHonorsR2 captures the fact that r2 is honored by the
11+
// runtime.GOARCH. Syscall conventions are generally r1, r2, err :=
12+
// syscall(trap, ...). Not all architectures define r2 in their
13+
// ABI. See "man syscall".
14+
const archHonorsR2 = false
15+
1016
const _SYS_setgroups = SYS_SETGROUPS
1117

1218
//sys Dup2(oldfd int, newfd int) (err error)

src/syscall/syscall_linux_riscv64.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ package syscall
66

77
import "unsafe"
88

9+
// archHonorsR2 captures the fact that r2 is honored by the
10+
// runtime.GOARCH. Syscall conventions are generally r1, r2, err :=
11+
// syscall(trap, ...). Not all architectures define r2 in their
12+
// ABI. See "man syscall".
13+
const archHonorsR2 = true
14+
915
const _SYS_setgroups = SYS_SETGROUPS
1016

1117
func EpollCreate(size int) (fd int, err error) {

src/syscall/syscall_linux_s390x.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ package syscall
66

77
import "unsafe"
88

9+
// archHonorsR2 captures the fact that r2 is honored by the
10+
// runtime.GOARCH. Syscall conventions are generally r1, r2, err :=
11+
// syscall(trap, ...). Not all architectures define r2 in their
12+
// ABI. See "man syscall".
13+
const archHonorsR2 = true
14+
915
const _SYS_setgroups = SYS_SETGROUPS
1016

1117
//sys Dup2(oldfd int, newfd int) (err error)

src/syscall/syscall_linux_test.go

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -410,9 +410,6 @@ const (
410410
// syscalls that execute on all OSThreads - with which to support
411411
// POSIX semantics for security state changes.
412412
func TestAllThreadsSyscall(t *testing.T) {
413-
if runtime.GOARCH == "ppc64" {
414-
t.Skip("skipping on linux/ppc64; see issue #42178")
415-
}
416413
if _, _, err := syscall.AllThreadsSyscall(syscall.SYS_PRCTL, PR_SET_KEEPCAPS, 0, 0); err == syscall.ENOTSUP {
417414
t.Skip("AllThreadsSyscall disabled with cgo")
418415
}
@@ -544,7 +541,7 @@ func TestAllThreadsSyscall(t *testing.T) {
544541
// compareStatus is used to confirm the contents of the thread
545542
// specific status files match expectations.
546543
func compareStatus(filter, expect string) error {
547-
expected := filter + "\t" + expect
544+
expected := filter + expect
548545
pid := syscall.Getpid()
549546
fs, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/task", pid))
550547
if err != nil {
@@ -553,14 +550,22 @@ func compareStatus(filter, expect string) error {
553550
for _, f := range fs {
554551
tf := fmt.Sprintf("/proc/%s/status", f.Name())
555552
d, err := ioutil.ReadFile(tf)
553+
if os.IsNotExist(err) {
554+
// We are racing against threads dying, which
555+
// is out of our control, so ignore the
556+
// missing file and skip to the next one.
557+
continue
558+
}
556559
if err != nil {
557560
return fmt.Errorf("unable to read %q: %v", tf, err)
558561
}
559562
lines := strings.Split(string(d), "\n")
560563
for _, line := range lines {
564+
// Different kernel vintages pad differently.
565+
line = strings.TrimSpace(line)
561566
if strings.HasPrefix(line, filter) {
562567
if line != expected {
563-
return fmt.Errorf("%s %s (bad)\n", tf, line)
568+
return fmt.Errorf("%q got:%q want:%q (bad)\n", tf, line, expected)
564569
}
565570
break
566571
}
@@ -580,9 +585,6 @@ func compareStatus(filter, expect string) error {
580585
// the syscalls. Care should be taken to mirror any enhancements to
581586
// this test here in that file too.
582587
func TestSetuidEtc(t *testing.T) {
583-
if runtime.GOARCH == "ppc64" {
584-
t.Skip("skipping on linux/ppc64; see issue #42178")
585-
}
586588
if syscall.Getuid() != 0 {
587589
t.Skip("skipping root only test")
588590
}
@@ -591,34 +593,34 @@ func TestSetuidEtc(t *testing.T) {
591593
fn func() error
592594
filter, expect string
593595
}{
594-
{call: "Setegid(1)", fn: func() error { return syscall.Setegid(1) }, filter: "Gid:", expect: "0\t1\t0\t1"},
595-
{call: "Setegid(0)", fn: func() error { return syscall.Setegid(0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
596+
{call: "Setegid(1)", fn: func() error { return syscall.Setegid(1) }, filter: "Gid:", expect: "\t0\t1\t0\t1"},
597+
{call: "Setegid(0)", fn: func() error { return syscall.Setegid(0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
596598

597-
{call: "Seteuid(1)", fn: func() error { return syscall.Seteuid(1) }, filter: "Uid:", expect: "0\t1\t0\t1"},
598-
{call: "Setuid(0)", fn: func() error { return syscall.Setuid(0) }, filter: "Uid:", expect: "0\t0\t0\t0"},
599+
{call: "Seteuid(1)", fn: func() error { return syscall.Seteuid(1) }, filter: "Uid:", expect: "\t0\t1\t0\t1"},
600+
{call: "Setuid(0)", fn: func() error { return syscall.Setuid(0) }, filter: "Uid:", expect: "\t0\t0\t0\t0"},
599601

600-
{call: "Setgid(1)", fn: func() error { return syscall.Setgid(1) }, filter: "Gid:", expect: "1\t1\t1\t1"},
601-
{call: "Setgid(0)", fn: func() error { return syscall.Setgid(0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
602+
{call: "Setgid(1)", fn: func() error { return syscall.Setgid(1) }, filter: "Gid:", expect: "\t1\t1\t1\t1"},
603+
{call: "Setgid(0)", fn: func() error { return syscall.Setgid(0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
602604

603-
{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 "},
604-
{call: "Setgroups(nil)", fn: func() error { return syscall.Setgroups(nil) }, filter: "Groups:", expect: " "},
605-
{call: "Setgroups([]int{0})", fn: func() error { return syscall.Setgroups([]int{0}) }, filter: "Groups:", expect: "0 "},
605+
{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"},
606+
{call: "Setgroups(nil)", fn: func() error { return syscall.Setgroups(nil) }, filter: "Groups:", expect: ""},
607+
{call: "Setgroups([]int{0})", fn: func() error { return syscall.Setgroups([]int{0}) }, filter: "Groups:", expect: "\t0"},
606608

607-
{call: "Setregid(101,0)", fn: func() error { return syscall.Setregid(101, 0) }, filter: "Gid:", expect: "101\t0\t0\t0"},
608-
{call: "Setregid(0,102)", fn: func() error { return syscall.Setregid(0, 102) }, filter: "Gid:", expect: "0\t102\t102\t102"},
609-
{call: "Setregid(0,0)", fn: func() error { return syscall.Setregid(0, 0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
609+
{call: "Setregid(101,0)", fn: func() error { return syscall.Setregid(101, 0) }, filter: "Gid:", expect: "\t101\t0\t0\t0"},
610+
{call: "Setregid(0,102)", fn: func() error { return syscall.Setregid(0, 102) }, filter: "Gid:", expect: "\t0\t102\t102\t102"},
611+
{call: "Setregid(0,0)", fn: func() error { return syscall.Setregid(0, 0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
610612

611-
{call: "Setreuid(1,0)", fn: func() error { return syscall.Setreuid(1, 0) }, filter: "Uid:", expect: "1\t0\t0\t0"},
612-
{call: "Setreuid(0,2)", fn: func() error { return syscall.Setreuid(0, 2) }, filter: "Uid:", expect: "0\t2\t2\t2"},
613-
{call: "Setreuid(0,0)", fn: func() error { return syscall.Setreuid(0, 0) }, filter: "Uid:", expect: "0\t0\t0\t0"},
613+
{call: "Setreuid(1,0)", fn: func() error { return syscall.Setreuid(1, 0) }, filter: "Uid:", expect: "\t1\t0\t0\t0"},
614+
{call: "Setreuid(0,2)", fn: func() error { return syscall.Setreuid(0, 2) }, filter: "Uid:", expect: "\t0\t2\t2\t2"},
615+
{call: "Setreuid(0,0)", fn: func() error { return syscall.Setreuid(0, 0) }, filter: "Uid:", expect: "\t0\t0\t0\t0"},
614616

615-
{call: "Setresgid(101,0,102)", fn: func() error { return syscall.Setresgid(101, 0, 102) }, filter: "Gid:", expect: "101\t0\t102\t0"},
616-
{call: "Setresgid(0,102,101)", fn: func() error { return syscall.Setresgid(0, 102, 101) }, filter: "Gid:", expect: "0\t102\t101\t102"},
617-
{call: "Setresgid(0,0,0)", fn: func() error { return syscall.Setresgid(0, 0, 0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
617+
{call: "Setresgid(101,0,102)", fn: func() error { return syscall.Setresgid(101, 0, 102) }, filter: "Gid:", expect: "\t101\t0\t102\t0"},
618+
{call: "Setresgid(0,102,101)", fn: func() error { return syscall.Setresgid(0, 102, 101) }, filter: "Gid:", expect: "\t0\t102\t101\t102"},
619+
{call: "Setresgid(0,0,0)", fn: func() error { return syscall.Setresgid(0, 0, 0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
618620

619-
{call: "Setresuid(1,0,2)", fn: func() error { return syscall.Setresuid(1, 0, 2) }, filter: "Uid:", expect: "1\t0\t2\t0"},
620-
{call: "Setresuid(0,2,1)", fn: func() error { return syscall.Setresuid(0, 2, 1) }, filter: "Uid:", expect: "0\t2\t1\t2"},
621-
{call: "Setresuid(0,0,0)", fn: func() error { return syscall.Setresuid(0, 0, 0) }, filter: "Uid:", expect: "0\t0\t0\t0"},
621+
{call: "Setresuid(1,0,2)", fn: func() error { return syscall.Setresuid(1, 0, 2) }, filter: "Uid:", expect: "\t1\t0\t2\t0"},
622+
{call: "Setresuid(0,2,1)", fn: func() error { return syscall.Setresuid(0, 2, 1) }, filter: "Uid:", expect: "\t0\t2\t1\t2"},
623+
{call: "Setresuid(0,0,0)", fn: func() error { return syscall.Setresuid(0, 0, 0) }, filter: "Uid:", expect: "\t0\t0\t0\t0"},
622624
}
623625

624626
for i, v := range vs {

0 commit comments

Comments
 (0)