Skip to content

Commit fed9a1b

Browse files
committed
fix: uniqMcs use all cpu
Signed-off-by: ningmingxiao <ning.mingxiao@zte.com.cn>
1 parent bc9c180 commit fed9a1b

8 files changed

Lines changed: 246 additions & 117 deletions

File tree

go-selinux/label/label_linux.go

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,11 @@ package label
22

33
import (
44
"errors"
5-
"fmt"
65
"strings"
76

87
"github.com/opencontainers/selinux/go-selinux"
98
)
109

11-
// Valid Label Options
12-
var validOptions = map[string]bool{
13-
"disable": true,
14-
"type": true,
15-
"filetype": true,
16-
"user": true,
17-
"role": true,
18-
"level": true,
19-
}
20-
2110
var ErrIncompatibleLabel = errors.New("bad SELinux option: z and Z can not be used together")
2211

2312
// InitLabels returns the process label and file labels to be used within
@@ -27,55 +16,7 @@ var ErrIncompatibleLabel = errors.New("bad SELinux option: z and Z can not be us
2716
// If the disabled flag is passed in, the process label will not be set, but the mount label will be set
2817
// to the container_file label with the maximum category. This label is not usable by any confined label.
2918
func InitLabels(options []string) (plabel string, mlabel string, retErr error) {
30-
if !selinux.GetEnabled() {
31-
return "", "", nil
32-
}
33-
processLabel, mountLabel := selinux.ContainerLabels()
34-
if processLabel == "" {
35-
// processLabel is required; if empty, do nothing.
36-
return processLabel, mountLabel, nil
37-
}
38-
defer func() {
39-
if retErr != nil {
40-
selinux.ReleaseLabel(mountLabel)
41-
}
42-
}()
43-
pcon, err := selinux.NewContext(processLabel)
44-
if err != nil {
45-
return "", "", err
46-
}
47-
mcsLevel := pcon["level"]
48-
mcon, err := selinux.NewContext(mountLabel)
49-
if err != nil {
50-
return "", "", err
51-
}
52-
for _, opt := range options {
53-
if opt == "disable" {
54-
selinux.ReleaseLabel(mountLabel)
55-
return "", selinux.PrivContainerMountLabel(), nil
56-
}
57-
k, v, ok := strings.Cut(opt, ":")
58-
if !ok || !validOptions[k] {
59-
return "", "", fmt.Errorf("bad label option %q, valid options 'disable' or \n'user, role, level, type, filetype' followed by ':' and a value", opt)
60-
}
61-
if k == "filetype" {
62-
mcon["type"] = v
63-
continue
64-
}
65-
pcon[k] = v
66-
if k == "level" || k == "user" {
67-
mcon[k] = v
68-
}
69-
}
70-
if p := pcon.Get(); p != processLabel {
71-
if pcon["level"] != mcsLevel {
72-
selinux.ReleaseLabel(processLabel)
73-
}
74-
selinux.ReserveLabel(p)
75-
processLabel = p
76-
}
77-
mountLabel = mcon.Get()
78-
return processLabel, mountLabel, nil
19+
return selinux.InitLabels(options)
7920
}
8021

8122
// SetFileLabel modifies the "path" label to the specified file label

go-selinux/label/label_linux_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package label
33
import (
44
"errors"
55
"os"
6+
"strings"
67
"testing"
78

89
"github.com/opencontainers/selinux/go-selinux"
@@ -53,6 +54,22 @@ func TestInit(t *testing.T) {
5354
}
5455
}
5556

57+
func TestSELinuxLabelExhaustion(t *testing.T) {
58+
needSELinux(t)
59+
selinux.CategoryRange = 5
60+
var testNull []string
61+
for i := 0; i < 20; i++ {
62+
_, _, err := InitLabels(testNull)
63+
if i == 19 {
64+
if err == nil {
65+
t.Fatal("err should not be nil")
66+
} else if !strings.Contains(err.Error(), "SELinux label exhaustion") {
67+
t.Fatalf("unexpected error %s", err.Error())
68+
}
69+
}
70+
}
71+
}
72+
5673
func TestRelabel(t *testing.T) {
5774
needSELinux(t)
5875

go-selinux/labels.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package selinux
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
)
7+
8+
// Valid Label Options
9+
var validOptions = map[string]bool{
10+
"disable": true,
11+
"type": true,
12+
"filetype": true,
13+
"user": true,
14+
"role": true,
15+
"level": true,
16+
}
17+
18+
// InitLabels returns the process label and file labels to be used within
19+
// the container. A list of options can be passed into this function to alter
20+
// the labels. The labels returned will include a random MCS String, that is
21+
// guaranteed to be unique.
22+
// If the disabled flag is passed in, the process label will not be set, but the mount label will be set
23+
// to the container_file label with the maximum category. This label is not usable by any confined label.
24+
func InitLabels(options []string) (plabel string, mlabel string, retErr error) {
25+
if !GetEnabled() {
26+
return "", "", nil
27+
}
28+
processLabel, mountLabel, err := containerLabels()
29+
if err != nil {
30+
return "", "", err
31+
}
32+
if processLabel == "" {
33+
// processLabel is required; if empty, do nothing.
34+
return processLabel, mountLabel, nil
35+
}
36+
defer func() {
37+
if retErr != nil {
38+
ReleaseLabel(mountLabel)
39+
}
40+
}()
41+
pcon, err := NewContext(processLabel)
42+
if err != nil {
43+
return "", "", err
44+
}
45+
mcsLevel := pcon["level"]
46+
mcon, err := NewContext(mountLabel)
47+
if err != nil {
48+
return "", "", err
49+
}
50+
for _, opt := range options {
51+
if opt == "disable" {
52+
ReleaseLabel(mountLabel)
53+
return "", PrivContainerMountLabel(), nil
54+
}
55+
k, v, ok := strings.Cut(opt, ":")
56+
if !ok || !validOptions[k] {
57+
return "", "", fmt.Errorf("bad label option %q, valid options 'disable' or \n'user, role, level, type, filetype' followed by ':' and a value", opt)
58+
}
59+
if k == "filetype" {
60+
mcon["type"] = v
61+
continue
62+
}
63+
pcon[k] = v
64+
if k == "level" || k == "user" {
65+
mcon[k] = v
66+
}
67+
}
68+
if p := pcon.Get(); p != processLabel {
69+
if pcon["level"] != mcsLevel {
70+
ReleaseLabel(processLabel)
71+
}
72+
ReserveLabel(p)
73+
processLabel = p
74+
}
75+
mountLabel = mcon.Get()
76+
return processLabel, mountLabel, nil
77+
}

go-selinux/selinux.go

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const (
2020
var (
2121
// ErrMCSAlreadyExists is returned when trying to allocate a duplicate MCS.
2222
ErrMCSAlreadyExists = errors.New("MCS label already exists")
23+
ErrMCSExhausted = errors.New("MCS label exhausted")
2324
// ErrEmptyPath is returned when an empty path has been specified.
2425
ErrEmptyPath = errors.New("empty path")
2526

@@ -217,8 +218,15 @@ func ClearLabels() {
217218
}
218219

219220
// ReserveLabel reserves the MLS/MCS level component of the specified label
221+
//
222+
// Deprecated: Use ReserveLabelV2 instead.
220223
func ReserveLabel(label string) {
221-
reserveLabel(label)
224+
_ = reserveLabel(label)
225+
}
226+
227+
// ReserveLabelV2 reserves the MLS/MCS level component of the specified label
228+
func ReserveLabelV2(label string) error {
229+
return reserveLabel(label)
222230
}
223231

224232
// CheckLabel check the MLS/MCS level component of the specified label
@@ -262,20 +270,32 @@ func ROFileLabel() string {
262270

263271
// KVMContainerLabels returns the default processLabel and mountLabel to be used
264272
// for kvm containers by the calling process.
273+
//
274+
// Deprecated: Use KVMContainerLabelsV2 instead.
265275
func KVMContainerLabels() (string, string) {
276+
processLabel, fileLabel, _ := kvmContainerLabels()
277+
return processLabel, fileLabel
278+
}
279+
280+
// KVMContainerLabelsV2 returns the default processLabel and mountLabel to be used
281+
// for kvm containers by the calling process.
282+
func KVMContainerLabelsV2() (processLabel, fileLabel string, err error) {
266283
return kvmContainerLabels()
267284
}
268285

269286
// InitContainerLabels returns the default processLabel and file labels to be
270287
// used for containers running an init system like systemd by the calling process.
288+
//
289+
// Deprecated: Use InitContainerLabelsV2 instead.
271290
func InitContainerLabels() (string, string) {
272-
return initContainerLabels()
291+
processLabel, fileLabel, _ := initContainerLabels()
292+
return processLabel, fileLabel
273293
}
274294

275-
// ContainerLabels returns an allocated processLabel and fileLabel to be used for
276-
// container labeling by the calling process.
277-
func ContainerLabels() (processLabel string, fileLabel string) {
278-
return containerLabels()
295+
// InitContainerLabelsV2 returns the default processLabel and file labels to be
296+
// used for containers running an init system like systemd by the calling process.
297+
func InitContainerLabelsV2() (processLabel, fileLabel string, err error) {
298+
return initContainerLabels()
279299
}
280300

281301
// SecurityCheckContext validates that the SELinux label is understood by the kernel
@@ -330,6 +350,6 @@ func GetDefaultContextWithLevel(user, level, scon string) (string, error) {
330350
// PrivContainerMountLabel returns mount label for privileged containers
331351
func PrivContainerMountLabel() string {
332352
// Make sure label is initialized.
333-
_ = label("")
353+
_, _ = label("")
334354
return privContainerMountLabel
335355
}

0 commit comments

Comments
 (0)