Merge pull request #873 from miaoyq/verify-selinux-level
Verify selinux level format
This commit is contained in:
@@ -21,6 +21,7 @@ import (
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -370,11 +371,16 @@ func initSelinuxOpts(selinuxOpt *runtime.SELinuxOption) (string, string, error)
|
||||
// Should ignored selinuxOpts if they are incomplete.
|
||||
if selinuxOpt.GetUser() == "" ||
|
||||
selinuxOpt.GetRole() == "" ||
|
||||
selinuxOpt.GetType() == "" ||
|
||||
selinuxOpt.GetLevel() == "" {
|
||||
selinuxOpt.GetType() == "" {
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
// make sure the format of "level" is correct.
|
||||
ok, err := checkSelinuxLevel(selinuxOpt.GetLevel())
|
||||
if err != nil || !ok {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
labelOpts := fmt.Sprintf("%s:%s:%s:%s",
|
||||
selinuxOpt.GetUser(),
|
||||
selinuxOpt.GetRole(),
|
||||
@@ -383,6 +389,18 @@ func initSelinuxOpts(selinuxOpt *runtime.SELinuxOption) (string, string, error)
|
||||
return label.InitLabels(selinux.DupSecOpt(labelOpts))
|
||||
}
|
||||
|
||||
func checkSelinuxLevel(level string) (bool, error) {
|
||||
if len(level) == 0 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
matched, err := regexp.MatchString(`^s\d(-s\d)??(:c\d{1,4}((.c\d{1,4})?,c\d{1,4})*(.c\d{1,4})?(,c\d{1,4}(.c\d{1,4})?)*)?$`, level)
|
||||
if err != nil || !matched {
|
||||
return false, fmt.Errorf("the format of 'level' %q is not correct: %v", level, err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// isInCRIMounts checks whether a destination is in CRI mount list.
|
||||
func isInCRIMounts(dst string, mounts []*runtime.Mount) bool {
|
||||
for _, m := range mounts {
|
||||
|
||||
@@ -19,6 +19,7 @@ limitations under the License.
|
||||
package server
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/opencontainers/selinux/go-selinux"
|
||||
@@ -35,6 +36,7 @@ func TestInitSelinuxOpts(t *testing.T) {
|
||||
selinuxOpt *runtime.SELinuxOption
|
||||
processLabel string
|
||||
mountLabels []string
|
||||
expectErr bool
|
||||
}{
|
||||
"Should return empty strings for processLabel and mountLabel when selinuxOpt is nil": {
|
||||
selinuxOpt: nil,
|
||||
@@ -61,12 +63,108 @@ func TestInitSelinuxOpts(t *testing.T) {
|
||||
processLabel: "user_u:user_r:user_t:s0:c1,c2",
|
||||
mountLabels: []string{"user_u:object_r:container_file_t:s0:c1,c2", "user_u:object_r:svirt_sandbox_file_t:s0:c1,c2"},
|
||||
},
|
||||
"Should be resolved correctly when selinuxOpt has been initialized with level=''": {
|
||||
selinuxOpt: &runtime.SELinuxOption{
|
||||
User: "user_u",
|
||||
Role: "user_r",
|
||||
Type: "user_t",
|
||||
Level: "",
|
||||
},
|
||||
processLabel: "user_u:user_r:user_t:s0",
|
||||
mountLabels: []string{"user_u:object_r:container_file_t:s0", "user_u:object_r:svirt_sandbox_file_t:s0"},
|
||||
},
|
||||
"Should return error when the format of 'level' is not correct": {
|
||||
selinuxOpt: &runtime.SELinuxOption{
|
||||
User: "user_u",
|
||||
Role: "user_r",
|
||||
Type: "user_t",
|
||||
Level: "s0,c1,c2",
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
} {
|
||||
t.Run(desc, func(t *testing.T) {
|
||||
processLabel, mountLabel, err := initSelinuxOpts(test.selinuxOpt)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, test.processLabel, processLabel)
|
||||
assert.Contains(t, test.mountLabels, mountLabel)
|
||||
if test.expectErr {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
if test.selinuxOpt == nil || test.selinuxOpt.Level != "" {
|
||||
assert.Equal(t, test.processLabel, processLabel)
|
||||
assert.Contains(t, test.mountLabels, mountLabel)
|
||||
} else {
|
||||
assert.Equal(t, 0, strings.LastIndex(processLabel, test.processLabel))
|
||||
contain := strings.LastIndex(mountLabel, test.mountLabels[0]) == 0 ||
|
||||
strings.LastIndex(mountLabel, test.mountLabels[1]) == 0
|
||||
assert.True(t, contain)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckSelinuxLevel(t *testing.T) {
|
||||
for desc, test := range map[string]struct {
|
||||
level string
|
||||
expectErr bool
|
||||
}{
|
||||
"s0": {
|
||||
level: "s0",
|
||||
},
|
||||
"s0-s0": {
|
||||
level: "s0-s0",
|
||||
},
|
||||
"s0:c0": {
|
||||
level: "s0:c0",
|
||||
},
|
||||
"s0:c0.c3": {
|
||||
level: "s0:c0.c3",
|
||||
},
|
||||
"s0:c0,c3": {
|
||||
level: "s0:c0,c3",
|
||||
},
|
||||
"s0-s0:c0,c3": {
|
||||
level: "s0-s0:c0,c3",
|
||||
},
|
||||
"s0-s0:c0,c3.c6": {
|
||||
level: "s0-s0:c0,c3.c6",
|
||||
},
|
||||
"s0-s0:c0,c3.c6,c8.c10": {
|
||||
level: "s0-s0:c0,c3.c6,c8.c10",
|
||||
},
|
||||
"s0-s0:c0,c3.c6,c8,c10": {
|
||||
level: "s0-s0:c0,c3.c6",
|
||||
},
|
||||
"s0,c0,c3": {
|
||||
level: "s0,c0,c3",
|
||||
expectErr: true,
|
||||
},
|
||||
"s0:c0.c3.c6": {
|
||||
level: "s0:c0.c3.c6",
|
||||
expectErr: true,
|
||||
},
|
||||
"s0-s0,c0,c3": {
|
||||
level: "s0-s0,c0,c3",
|
||||
expectErr: true,
|
||||
},
|
||||
"s0-s0:c0.c3.c6": {
|
||||
level: "s0-s0:c0.c3.c6",
|
||||
expectErr: true,
|
||||
},
|
||||
"s0-s0:c0,c3.c6.c8": {
|
||||
level: "s0-s0:c0,c3.c6.c8",
|
||||
expectErr: true,
|
||||
},
|
||||
} {
|
||||
t.Run(desc, func(t *testing.T) {
|
||||
ok, err := checkSelinuxLevel(test.level)
|
||||
if test.expectErr {
|
||||
assert.Error(t, err)
|
||||
assert.False(t, ok)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user