Skip to content

Commit 965323e

Browse files
committed
SetKeyLabel: add thread group leader requirement
Since commit bbbc51c ("Need to set process attributes not task") SetKeyLabel and KeyLabel operate on /proc/self/attr/keycreate, which can only be modified by the thread group leader; a non thread group leader thread will get EACCES: > write /proc/self/attr/keycreate: permission denied Let's document that, and return a more meaningful error (ErrNotTGLeader) if that is the case. Modify the test case accordingly, i.e. skip it if the current thread is not the thread group leader. Signed-off-by: Kir Kolyshkin <[email protected]>
1 parent 4c76c01 commit 965323e

File tree

3 files changed

+27
-4
lines changed

3 files changed

+27
-4
lines changed

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

+12
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"strconv"
1212
"strings"
1313
"testing"
14+
15+
"golang.org/x/sys/unix"
1416
)
1517

1618
func TestSetFileLabel(t *testing.T) {
@@ -212,6 +214,16 @@ func TestKeyLabel(t *testing.T) {
212214
t.Skip("SELinux not enabled, skipping.")
213215
}
214216

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+
215227
label := "system_u:object_r:container_t:s0:c1,c2"
216228
if err := SetKeyLabel(label); err != nil {
217229
t.Fatal(err)

0 commit comments

Comments
 (0)