Skip to content

Commit 996c4cf

Browse files
authored
Merge pull request #227 from kolyshkin/fix-flake
Improve SetKeyCreate error reporting, fix test flakes
2 parents 03cde75 + 2a69eaf commit 996c4cf

File tree

4 files changed

+53
-15
lines changed

4 files changed

+53
-15
lines changed

.github/workflows/validate.yml

+6
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ jobs:
140140
continue-on-error: true
141141
run: lima make -C /tmp/selinux GOARCH=386 test
142142

143+
# https://github.com/opencontainers/selinux/issues/222
144+
# https://github.com/opencontainers/selinux/issues/225
145+
- name: "racy test"
146+
continue-on-error: true
147+
run: lima bash -c 'cd /tmp/selinux && go test -timeout 10m -count 100000 ./go-selinux'
148+
143149
- name: "Show AVC denials"
144150
run: lima sudo ausearch -m AVC,USER_AVC || true
145151

go-selinux/selinux.go

+12-4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ var (
4141
// ErrVerifierNil is returned when a context verifier function is nil.
4242
ErrVerifierNil = errors.New("verifier function is nil")
4343

44+
// ErrNotTGLeader is returned by [SetKeyLabel] if the calling thread
45+
// is not the thread group leader.
46+
ErrNotTGLeader = errors.New("calling thread is not the thread group leader")
47+
4448
// CategoryRange allows the upper bound on the category range to be adjusted
4549
CategoryRange = DefaultCategoryRange
4650

@@ -180,10 +184,14 @@ func PeerLabel(fd uintptr) (string, error) {
180184
}
181185

182186
// SetKeyLabel takes a process label and tells the kernel to assign the
183-
// label to the next kernel keyring that gets created. Calls to SetKeyLabel
184-
// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until
185-
// the kernel keyring is created to guarantee another goroutine does not migrate
186-
// to the current thread before execution is complete.
187+
// label to the next kernel keyring that gets created.
188+
//
189+
// Calls to SetKeyLabel should be wrapped in
190+
// runtime.LockOSThread()/runtime.UnlockOSThread() until the kernel keyring is
191+
// created to guarantee another goroutine does not migrate to the current
192+
// thread before execution is complete.
193+
//
194+
// Only the thread group leader can set key label.
187195
func SetKeyLabel(label string) error {
188196
return setKeyLabel(label)
189197
}

go-selinux/selinux_linux.go

+3
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,9 @@ func setKeyLabel(label string) error {
735735
if label == "" && errors.Is(err, os.ErrPermission) {
736736
return nil
737737
}
738+
if errors.Is(err, unix.EACCES) && unix.Getuid() != unix.Gettid() {
739+
return ErrNotTGLeader
740+
}
738741
return err
739742
}
740743

go-selinux/selinux_linux_test.go

+32-11
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ import (
77
"fmt"
88
"os"
99
"path/filepath"
10+
"runtime"
1011
"strconv"
1112
"strings"
1213
"testing"
14+
15+
"golang.org/x/sys/unix"
1316
)
1417

1518
func TestSetFileLabel(t *testing.T) {
@@ -187,6 +190,12 @@ func TestSocketLabel(t *testing.T) {
187190
t.Skip("SELinux not enabled, skipping.")
188191
}
189192

193+
// Ensure the thread stays the same for duration of the test.
194+
// Otherwise Go runtime can switch this to a different thread,
195+
// which results in EACCES in call to SetSocketLabel.
196+
runtime.LockOSThread()
197+
defer runtime.UnlockOSThread()
198+
190199
label := "system_u:object_r:container_t:s0:c1,c2"
191200
if err := SetSocketLabel(label); err != nil {
192201
t.Fatal(err)
@@ -205,6 +214,16 @@ func TestKeyLabel(t *testing.T) {
205214
t.Skip("SELinux not enabled, skipping.")
206215
}
207216

217+
// Ensure the thread stays the same for duration of the test.
218+
// Otherwise Go runtime can switch this to a different thread,
219+
// which results in EACCES in call to SetKeyLabel.
220+
runtime.LockOSThread()
221+
defer runtime.UnlockOSThread()
222+
223+
if unix.Getpid() != unix.Gettid() {
224+
t.Skip(ErrNotTGLeader)
225+
}
226+
208227
label := "system_u:object_r:container_t:s0:c1,c2"
209228
if err := SetKeyLabel(label); err != nil {
210229
t.Fatal(err)
@@ -235,6 +254,12 @@ func TestSELinux(t *testing.T) {
235254
t.Skip("SELinux not enabled, skipping.")
236255
}
237256

257+
// Ensure the thread stays the same for duration of the test.
258+
// Otherwise Go runtime can switch this to a different thread,
259+
// which results in EACCES in call to SetFSCreateLabel.
260+
runtime.LockOSThread()
261+
defer runtime.UnlockOSThread()
262+
238263
var (
239264
err error
240265
plabel, flabel string
@@ -259,21 +284,17 @@ func TestSELinux(t *testing.T) {
259284
ReleaseLabel(plabel)
260285

261286
pid := os.Getpid()
262-
t.Logf("PID:%d MCS:%s\n", pid, intToMcs(pid, 1023))
287+
t.Logf("PID:%d MCS:%s", pid, intToMcs(pid, 1023))
263288
err = SetFSCreateLabel("unconfined_u:unconfined_r:unconfined_t:s0")
264-
if err == nil {
265-
t.Log(FSCreateLabel())
266-
} else {
267-
t.Log("SetFSCreateLabel failed", err)
268-
t.Fatal(err)
289+
if err != nil {
290+
t.Fatal("SetFSCreateLabel failed:", err)
269291
}
292+
t.Log(FSCreateLabel())
270293
err = SetFSCreateLabel("")
271-
if err == nil {
272-
t.Log(FSCreateLabel())
273-
} else {
274-
t.Log("SetFSCreateLabel failed", err)
275-
t.Fatal(err)
294+
if err != nil {
295+
t.Fatal("SetFSCreateLabel failed:", err)
276296
}
297+
t.Log(FSCreateLabel())
277298
t.Log(PidLabel(1))
278299
}
279300

0 commit comments

Comments
 (0)