Skip to content

Commit 88a4437

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 360b2a3 commit 88a4437

File tree

3 files changed

+27
-4
lines changed

3 files changed

+27
-4
lines changed

go-selinux/label/label_linux_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"strings"
88
"testing"
99

10+
"golang.org/x/sys/unix"
11+
1012
"github.com/opencontainers/selinux/go-selinux"
1113
)
1214

@@ -204,6 +206,16 @@ func TestSocketLabel(t *testing.T) {
204206
func TestKeyLabel(t *testing.T) {
205207
needSELinux(t)
206208

209+
// Ensure the thread stays the same for duration of the test.
210+
// Otherwise Go runtime can switch this to a different thread,
211+
// which results in EACCES in call to SetKeyLabel.
212+
runtime.LockOSThread()
213+
defer runtime.UnlockOSThread()
214+
215+
if unix.Getpid() != unix.Gettid() {
216+
t.Skip(selinux.ErrNotTGLeader)
217+
}
218+
207219
label := "system_u:object_r:container_t:s0:c1,c2"
208220
if err := selinux.SetKeyLabel(label); err != nil {
209221
t.Fatal(err)

go-selinux/selinux.go

Lines changed: 12 additions & 4 deletions
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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,9 @@ func setKeyLabel(label string) error {
731731
if label == "" && errors.Is(err, os.ErrPermission) {
732732
return nil
733733
}
734+
if errors.Is(err, unix.EACCES) && unix.Getuid() != unix.Gettid() {
735+
return ErrNotTGLeader
736+
}
734737
return err
735738
}
736739

0 commit comments

Comments
 (0)