Add MCS label support
Carry of #1246 Signed-off-by: Darren Shepherd <darren@rancher.com> Signed-off-by: Michael Crosby <michael@thepasture.io>
This commit is contained in:
committed by
Michael Crosby
parent
40071878d7
commit
24209b91bf
90
pkg/store/label/label.go
Normal file
90
pkg/store/label/label.go
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package label
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/opencontainers/selinux/go-selinux"
|
||||
)
|
||||
|
||||
type Store struct {
|
||||
sync.Mutex
|
||||
levels map[string]int
|
||||
Releaser func(string)
|
||||
Reserver func(string)
|
||||
}
|
||||
|
||||
func NewStore() *Store {
|
||||
return &Store{
|
||||
levels: map[string]int{},
|
||||
Releaser: selinux.ReleaseLabel,
|
||||
Reserver: selinux.ReserveLabel,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) Reserve(label string) error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
context, err := selinux.NewContext(label)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
level := context["level"]
|
||||
// no reason to count empty
|
||||
if level == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, ok := s.levels[level]; !ok {
|
||||
s.Reserver(label)
|
||||
}
|
||||
|
||||
s.levels[level]++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) Release(label string) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
context, err := selinux.NewContext(label)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
level := context["level"]
|
||||
if level == "" {
|
||||
return
|
||||
}
|
||||
|
||||
count, ok := s.levels[level]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
switch {
|
||||
case count == 1:
|
||||
s.Releaser(label)
|
||||
delete(s.levels, level)
|
||||
case count < 1:
|
||||
delete(s.levels, level)
|
||||
case count > 1:
|
||||
s.levels[level] = count - 1
|
||||
}
|
||||
}
|
||||
116
pkg/store/label/label_test.go
Normal file
116
pkg/store/label/label_test.go
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package label
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/opencontainers/selinux/go-selinux"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAddThenRemove(t *testing.T) {
|
||||
if !selinux.GetEnabled() {
|
||||
t.Skip("selinux is not enabled")
|
||||
}
|
||||
|
||||
assert := assert.New(t)
|
||||
store := NewStore()
|
||||
releaseCount := 0
|
||||
reserveCount := 0
|
||||
store.Releaser = func(label string) {
|
||||
assert.Contains(label, ":c1,c2")
|
||||
releaseCount++
|
||||
assert.Equal(1, releaseCount)
|
||||
}
|
||||
store.Reserver = func(label string) {
|
||||
assert.Contains(label, ":c1,c2")
|
||||
reserveCount++
|
||||
assert.Equal(1, reserveCount)
|
||||
}
|
||||
|
||||
t.Log("should count to two level")
|
||||
assert.NoError(store.Reserve("junk:junk:junk:c1,c2"))
|
||||
assert.NoError(store.Reserve("junk2:junk2:junk2:c1,c2"))
|
||||
|
||||
t.Log("should have one item")
|
||||
assert.Equal(1, len(store.levels))
|
||||
|
||||
t.Log("c1,c2 count should be 2")
|
||||
assert.Equal(2, store.levels["c1,c2"])
|
||||
|
||||
store.Release("junk:junk:junk:c1,c2")
|
||||
store.Release("junk2:junk2:junk2:c1,c2")
|
||||
|
||||
t.Log("should have 0 items")
|
||||
assert.Equal(0, len(store.levels))
|
||||
|
||||
t.Log("should have reserved")
|
||||
assert.Equal(1, reserveCount)
|
||||
|
||||
t.Log("should have released")
|
||||
assert.Equal(1, releaseCount)
|
||||
}
|
||||
|
||||
func TestJunkData(t *testing.T) {
|
||||
if !selinux.GetEnabled() {
|
||||
t.Skip("selinux is not enabled")
|
||||
}
|
||||
|
||||
assert := assert.New(t)
|
||||
store := NewStore()
|
||||
releaseCount := 0
|
||||
store.Releaser = func(label string) {
|
||||
releaseCount++
|
||||
}
|
||||
reserveCount := 0
|
||||
store.Reserver = func(label string) {
|
||||
reserveCount++
|
||||
}
|
||||
|
||||
t.Log("should ignore empty label")
|
||||
assert.NoError(store.Reserve(""))
|
||||
assert.Equal(0, len(store.levels))
|
||||
store.Release("")
|
||||
assert.Equal(0, len(store.levels))
|
||||
assert.Equal(0, releaseCount)
|
||||
assert.Equal(0, reserveCount)
|
||||
|
||||
t.Log("should fail on bad label")
|
||||
assert.Error(store.Reserve("junkjunkjunkc1c2"))
|
||||
assert.Equal(0, len(store.levels))
|
||||
store.Release("junkjunkjunkc1c2")
|
||||
assert.Equal(0, len(store.levels))
|
||||
assert.Equal(0, releaseCount)
|
||||
assert.Equal(0, reserveCount)
|
||||
|
||||
t.Log("should not release unknown label")
|
||||
store.Release("junk2:junk2:junk2:c1,c2")
|
||||
assert.Equal(0, len(store.levels))
|
||||
assert.Equal(0, releaseCount)
|
||||
assert.Equal(0, reserveCount)
|
||||
|
||||
t.Log("should release once even if too many deletes")
|
||||
assert.NoError(store.Reserve("junk2:junk2:junk2:c1,c2"))
|
||||
assert.Equal(1, len(store.levels))
|
||||
assert.Equal(1, store.levels["c1,c2"])
|
||||
store.Release("junk2:junk2:junk2:c1,c2")
|
||||
store.Release("junk2:junk2:junk2:c1,c2")
|
||||
assert.Equal(0, len(store.levels))
|
||||
assert.Equal(1, releaseCount)
|
||||
assert.Equal(1, reserveCount)
|
||||
}
|
||||
Reference in New Issue
Block a user