Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flaky test on Fedora: TestKeyLabel: write /proc/self/attr/keycreate: permission denied #222

Open
AkihiroSuda opened this issue Mar 7, 2025 · 2 comments

Comments

@AkihiroSuda
Copy link
Member

AkihiroSuda commented Mar 7, 2025

Flaky test on Fedora

=== RUN   TestKeyLabel
    label_linux_test.go:202: write /proc/self/attr/keycreate: permission denied
--- FAIL: TestKeyLabel (0.00s)

Originally posted by @AkihiroSuda in #221 (comment)

@kolyshkin
Copy link
Collaborator

I spent some time looking at it this week, and it seems that

  • it is related to Fedora / latest kernel;
  • it is easy to reproduce

Here's a quick repro:

[kir@kir-tp1 selinux]$ pwd
/home/kir/git/opencontainers/selinux
[kir@kir-tp1 selinux]$ go test -count 1000 -run KeyLabel ./go-selinux/label/

I run it on my Fedora 41 laptop and I'm getting frequent failures. If you don't, feel free to increase count or run it again.

I also tried to add retries (into two different places) and it doesn't help. Here's my ugly retrials+debug code:

diff --git a/go-selinux/selinux_linux.go b/go-selinux/selinux_linux.go
index be139a4..7702596 100644
--- a/go-selinux/selinux_linux.go
+++ b/go-selinux/selinux_linux.go
@@ -16,6 +16,7 @@ import (
 	"strconv"
 	"strings"
 	"sync"
+	"time"
 
 	"github.com/opencontainers/selinux/pkg/pwalkdir"
 	"golang.org/x/sys/unix"
@@ -437,12 +438,22 @@ func writeCon(fpath, val string) error {
 		return err
 	}
 
+	i := 0
+again:
 	if val != "" {
 		_, err = out.Write([]byte(val))
 	} else {
 		_, err = out.Write(nil)
 	}
 	if err != nil {
+		if errors.Is(err, unix.EACCES) {
+			i++
+			if i < 10 {
+				print("writeCon: got EACCES, retry ", i, "\n")
+				time.Sleep(100 * time.Nanosecond)
+				goto again
+			}
+		}
 		return err
 	}
 	return nil
@@ -711,12 +722,21 @@ func peerLabel(fd uintptr) (string, error) {
 // setKeyLabel takes a process label and tells the kernel to assign the
 // label to the next kernel keyring that gets created
 func setKeyLabel(label string) error {
-	err := writeCon("/proc/self/attr/keycreate", label)
-	if errors.Is(err, os.ErrNotExist) {
-		return nil
-	}
-	if label == "" && errors.Is(err, os.ErrPermission) {
-		return nil
+	var err error
+	for i := 0; i < 25; i++ {
+		err = writeCon("/proc/self/attr/keycreate", label)
+		if errors.Is(err, os.ErrNotExist) {
+			return nil
+		}
+		if errors.Is(err, unix.EACCES) {
+			print("setKeyLabel: got EACCES, retry ", i, "\n")
+			time.Sleep(10 * time.Nanosecond)
+			continue
+		}
+		if label == "" && errors.Is(err, os.ErrPermission) {
+			return nil
+		}
+		return err
 	}
 	return err
 }

Here's what I'm seeing:

=== RUN   TestKeyLabel
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 0
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 1
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 2
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 3
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 4
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 5
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 6
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 7
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 8
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 9
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 10
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 11
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 12
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 13
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 14
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 15
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 16
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 17
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 18
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 19
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 20
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 21
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 22
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 23
writeCon: got EACCES, retry 1
writeCon: got EACCES, retry 2
writeCon: got EACCES, retry 3
writeCon: got EACCES, retry 4
writeCon: got EACCES, retry 5
writeCon: got EACCES, retry 6
writeCon: got EACCES, retry 7
writeCon: got EACCES, retry 8
writeCon: got EACCES, retry 9
setKeyLabel: got EACCES, retry 24
    label_linux_test.go:202: write /proc/self/attr/keycreate: permission denied

I also tried using runtime.LockOSThread(), didn't help either.

The fact that this only

@AkihiroSuda
Copy link
Member Author

it is related to Fedora / latest kernel;

The issue seems to happen on AlmaLinux 8 too
https://github.com/opencontainers/selinux/actions/runs/13740062867/job/38428218382#step:7:79

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants