Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions pkg/annotations/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ const (

// OCISeccompBPFHookAnnotation is the annotation used by the OCI seccomp BPF hook for tracing container syscalls
OCISeccompBPFHookAnnotation = "io.containers.trace-syscall"

// TrySkipVolumeSELinuxLabelAnnotation is the annotation used for optionally skipping relabeling a volume
// with the specified SELinux label. The relabeling will be skipped if the top layer is already labeled correctly.
TrySkipVolumeSELinuxLabelAnnotation = "io.kubernetes.cri-o.TrySkipVolumeSELinuxLabel"
)

var AllAllowedAnnotations = []string{
Expand All @@ -43,4 +47,5 @@ var AllAllowedAnnotations = []string{
IRQLoadBalancingAnnotation,
OCISeccompBPFHookAnnotation,
rdt.RdtContainerAnnotation,
TrySkipVolumeSELinuxLabelAnnotation,
}
6 changes: 3 additions & 3 deletions server/container_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func addImageVolumes(ctx context.Context, rootfs string, s *Server, containerInf
return nil, err1
}
if mountLabel != "" {
if err1 := securityLabel(fp, mountLabel, true); err1 != nil {
if err1 := securityLabel(fp, mountLabel, true, false); err1 != nil {
return nil, err1
}
}
Expand All @@ -143,7 +143,7 @@ func addImageVolumes(ctx context.Context, rootfs string, s *Server, containerInf
}
// Label the source with the sandbox selinux mount label
if mountLabel != "" {
if err1 := securityLabel(src, mountLabel, true); err1 != nil {
if err1 := securityLabel(src, mountLabel, true, false); err1 != nil {
return nil, err1
}
}
Expand Down Expand Up @@ -235,7 +235,7 @@ func setupContainerUser(ctx context.Context, specgen *generate.Generator, rootfs
return err
}
if passwdPath != "" {
if err := securityLabel(passwdPath, mountLabel, false); err != nil {
if err := securityLabel(passwdPath, mountLabel, false, false); err != nil {
return err
}

Expand Down
34 changes: 22 additions & 12 deletions server/container_create_linux.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build linux
// +build linux

package server
Expand Down Expand Up @@ -135,6 +136,14 @@ func (s *Server) createSandboxContainer(ctx context.Context, ctr ctrIface.Contai

// eventually, we'd like to access all of these variables through the interface themselves, and do most
// of the translation between CRI config -> oci/storage container in the container package

// TODO: eventually, this should be in the container package, but it's going through a lot of churn
// and SpecAddAnnotations is already being passed too many arguments
// Filter early so any use of the annotations don't use the wrong values
if err := s.Runtime().FilterDisallowedAnnotations(sb.RuntimeHandler(), ctr.Config().Annotations); err != nil {
return nil, err
}

containerID := ctr.ID()
containerName := ctr.Name()
containerConfig := ctr.Config()
Expand Down Expand Up @@ -268,7 +277,12 @@ func (s *Server) createSandboxContainer(ctx context.Context, ctr ctrIface.Contai
processLabel = ""
}

containerVolumes, ociMounts, err := addOCIBindMounts(ctx, mountLabel, containerConfig, specgen, s.config.RuntimeConfig.BindMountPrefix, s.config.AbsentMountSourcesToReject)
maybeRelabel := false
if val, present := sb.Annotations()[crioann.TrySkipVolumeSELinuxLabelAnnotation]; present && val == "true" {
maybeRelabel = true
}

containerVolumes, ociMounts, err := addOCIBindMounts(ctx, ctr, mountLabel, s.config.RuntimeConfig.BindMountPrefix, s.config.AbsentMountSourcesToReject, maybeRelabel)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -525,7 +539,7 @@ func (s *Server) createSandboxContainer(ctx context.Context, ctr ctrIface.Contai
options = []string{"ro"}
}
if sb.ResolvPath() != "" {
if err := securityLabel(sb.ResolvPath(), mountLabel, false); err != nil {
if err := securityLabel(sb.ResolvPath(), mountLabel, false, false); err != nil {
return nil, err
}
ctr.SpecAddMount(rspec.Mount{
Expand All @@ -537,7 +551,7 @@ func (s *Server) createSandboxContainer(ctx context.Context, ctr ctrIface.Contai
}

if sb.HostnamePath() != "" {
if err := securityLabel(sb.HostnamePath(), mountLabel, false); err != nil {
if err := securityLabel(sb.HostnamePath(), mountLabel, false, false); err != nil {
return nil, err
}
ctr.SpecAddMount(rspec.Mount{
Expand Down Expand Up @@ -592,12 +606,6 @@ func (s *Server) createSandboxContainer(ctx context.Context, ctr ctrIface.Contai
}
}()

// TODO: eventually, this should be in the container package, but it's going through a lot of churn
// and SpecAddAnnotations is already passed too many arguments
if err := s.Runtime().FilterDisallowedAnnotations(sb.RuntimeHandler(), ctr.Config().Annotations); err != nil {
return nil, err
}

// Get RDT class
rdtClass, err := s.Config().Rdt().ContainerClassFromAnnotations(metadata.Name, containerConfig.Annotations, sb.Annotations())
if err != nil {
Expand Down Expand Up @@ -796,7 +804,7 @@ func setupWorkingDirectory(rootfs, mountLabel, containerCwd string) error {
return err
}
if mountLabel != "" {
if err1 := securityLabel(fp, mountLabel, false); err1 != nil {
if err1 := securityLabel(fp, mountLabel, false, false); err1 != nil {
return err1
}
}
Expand Down Expand Up @@ -826,9 +834,11 @@ func clearReadOnly(m *rspec.Mount) {
m.Options = append(m.Options, "rw")
}

func addOCIBindMounts(ctx context.Context, mountLabel string, containerConfig *types.ContainerConfig, specgen *generate.Generator, bindMountPrefix string, absentMountSourcesToReject []string) ([]oci.ContainerVolume, []rspec.Mount, error) {
func addOCIBindMounts(ctx context.Context, ctr ctrIface.Container, mountLabel, bindMountPrefix string, absentMountSourcesToReject []string, maybeRelabel bool) ([]oci.ContainerVolume, []rspec.Mount, error) {
volumes := []oci.ContainerVolume{}
ociMounts := []rspec.Mount{}
containerConfig := ctr.Config()
specgen := ctr.Spec()
mounts := containerConfig.Mounts

// Sort mounts in number of parts. This ensures that high level mounts don't
Expand Down Expand Up @@ -934,7 +944,7 @@ func addOCIBindMounts(ctx context.Context, mountLabel string, containerConfig *t
}

if m.SelinuxRelabel {
if err := securityLabel(src, mountLabel, false); err != nil {
if err := securityLabel(src, mountLabel, false, maybeRelabel); err != nil {
return nil, nil, err
}
}
Expand Down
37 changes: 29 additions & 8 deletions server/container_create_linux_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build linux
// +build linux

package server
Expand All @@ -6,28 +7,38 @@ import (
"context"
"testing"

"github.com/cri-o/cri-o/pkg/container"
"github.com/cri-o/cri-o/server/cri/types"
"github.com/opencontainers/runtime-tools/generate"
)

func TestAddOCIBindsForDev(t *testing.T) {
specgen, err := generate.New("linux")
ctr, err := container.New()
if err != nil {
t.Error(err)
}
config := &types.ContainerConfig{
if err := ctr.SetConfig(&types.ContainerConfig{
Mounts: []*types.Mount{
{
ContainerPath: "/dev",
HostPath: "/dev",
},
},
Metadata: &types.ContainerMetadata{
Name: "testctr",
},
}, &types.PodSandboxConfig{
Metadata: &types.PodSandboxMetadata{
Name: "testpod",
},
}); err != nil {
t.Error(err)
}
_, binds, err := addOCIBindMounts(context.Background(), "", config, &specgen, "", nil)

_, binds, err := addOCIBindMounts(context.Background(), ctr, "", "", nil, false)
if err != nil {
t.Error(err)
}
for _, m := range specgen.Mounts() {
for _, m := range ctr.Spec().Mounts() {
if m.Destination == "/dev" {
t.Error("/dev shouldn't be in the spec if it's bind mounted from kube")
}
Expand All @@ -45,19 +56,29 @@ func TestAddOCIBindsForDev(t *testing.T) {
}

func TestAddOCIBindsForSys(t *testing.T) {
specgen, err := generate.New("linux")
ctr, err := container.New()
if err != nil {
t.Error(err)
}
config := &types.ContainerConfig{
if err := ctr.SetConfig(&types.ContainerConfig{
Mounts: []*types.Mount{
{
ContainerPath: "/sys",
HostPath: "/sys",
},
},
Metadata: &types.ContainerMetadata{
Name: "testctr",
},
}, &types.PodSandboxConfig{
Metadata: &types.PodSandboxMetadata{
Name: "testpod",
},
}); err != nil {
t.Error(err)
}
_, binds, err := addOCIBindMounts(context.Background(), "", config, &specgen, "", nil)

_, binds, err := addOCIBindMounts(context.Background(), ctr, "", "", nil, false)
if err != nil {
t.Error(err)
}
Expand Down
12 changes: 11 additions & 1 deletion server/label_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,20 @@ import (

"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)

func securityLabel(path, secLabel string, shared bool) error {
func securityLabel(path, secLabel string, shared, maybeRelabel bool) error {
if maybeRelabel {
currentLabel, err := label.FileLabel(path)
if err == nil && currentLabel == secLabel {
logrus.Debugf(
"Skipping relabel for %s, as TrySkipVolumeSELinuxRelabel is true and the label of the top level of the volume is already correct",
path)
return nil
}
}
if err := label.Relabel(path, secLabel, shared); err != nil && !errors.Is(err, unix.ENOTSUP) {
return fmt.Errorf("relabel failed %s: %v", path, err)
}
Expand Down
3 changes: 2 additions & 1 deletion server/label_unsupported.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//go:build !linux
// +build !linux

package server

func securityLabel(path string, seclabel string, shared bool) error {
func securityLabel(path string, seclabel string, shared, maybeRelabel bool) error {
return nil
}
20 changes: 4 additions & 16 deletions test/devices.bats
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,6 @@ function teardown() {
cleanup_test
}

function create_device_runtime() {
cat << EOF > "$CRIO_CONFIG_DIR/01-device.conf"
[crio.runtime]
default_runtime = "device"
[crio.runtime.runtimes.device]
runtime_path = "$RUNTIME_BINARY_PATH"
runtime_root = "$RUNTIME_ROOT"
runtime_type = "$RUNTIME_TYPE"
allowed_annotations = ["io.kubernetes.cri-o.Devices"]
EOF
}

@test "additional devices support" {
OVERRIDE_OPTIONS="--additional-devices /dev/null:/dev/qifoo:rwm" start_crio
pod_id=$(crictl runp "$TESTDATA"/sandbox_config.json)
Expand Down Expand Up @@ -80,7 +68,7 @@ EOF
}

@test "annotation devices support" {
create_device_runtime
create_runtime_with_allowed_annotation "device" "io.kubernetes.cri-o.Devices"
start_crio

jq ' .annotations."io.kubernetes.cri-o.Devices" = "/dev/null:/dev/qifoo:rwm"' \
Expand Down Expand Up @@ -110,7 +98,7 @@ EOF
}

@test "annotation should override configured additional_devices" {
create_device_runtime
create_runtime_with_allowed_annotation "device" "io.kubernetes.cri-o.Devices"

OVERRIDE_OPTIONS="--additional-devices /dev/urandom:/dev/qifoo:rwm" start_crio

Expand All @@ -128,7 +116,7 @@ EOF
}

@test "annotation should configure multiple devices" {
create_device_runtime
create_runtime_with_allowed_annotation "device" "io.kubernetes.cri-o.Devices"
start_crio

jq ' .annotations."io.kubernetes.cri-o.Devices" = "/dev/null:/dev/qifoo:rwm,/dev/urandom:/dev/peterfoo:rwm"' \
Expand All @@ -147,7 +135,7 @@ EOF
}

@test "annotation should fail if one device is invalid" {
create_device_runtime
create_runtime_with_allowed_annotation "device" "io.kubernetes.cri-o.Devices"
start_crio

jq ' .annotations."io.kubernetes.cri-o.Devices" = "/dev/null:/dev/qifoo:rwm,/dove/null"' \
Expand Down
14 changes: 14 additions & 0 deletions test/helpers.bash
Original file line number Diff line number Diff line change
Expand Up @@ -548,3 +548,17 @@ function fail() {
function is_cgroup_v2() {
test "$(stat -f -c%T /sys/fs/cgroup)" = "cgroup2fs"
}

function create_runtime_with_allowed_annotation() {
local NAME="$1"
local ANNOTATION="$2"
cat <<EOF >"$CRIO_CONFIG_DIR/01-$NAME.conf"
[crio.runtime]
default_runtime = "$NAME"
[crio.runtime.runtimes.$NAME]
runtime_path = "$RUNTIME_BINARY_PATH"
runtime_root = "$RUNTIME_ROOT"
runtime_type = "$RUNTIME_TYPE"
allowed_annotations = ["$ANNOTATION"]
EOF
}
45 changes: 45 additions & 0 deletions test/selinux.bats
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,48 @@ function teardown() {
ctr_id=$(crictl create "$pod_id" "$TESTDATA"/container_redis.json "$TESTDIR"/sandbox.json)
crictl start "$ctr_id"
}

@test "selinux skips relabeling if TrySkipVolumeSELinuxLabel annotation is present" {
if [[ $(getenforce) != "Enforcing" ]]; then
skip "not enforcing"
fi
VOLUME="$TESTDIR"/dir
mkdir "$VOLUME"
touch "$VOLUME"/file

create_runtime_with_allowed_annotation "selinux" "io.kubernetes.cri-o.TrySkipVolumeSELinuxLabel"
start_crio

jq ' .linux.security_context.selinux_options = {"level": "s0:c100,c200"}
| .annotations["io.kubernetes.cri-o.TrySkipVolumeSELinuxLabel"] = "true"' \
"$TESTDATA"/sandbox_config.json > "$TESTDIR"/sandbox.json

jq --arg path "$VOLUME" \
' .mounts = [ {
host_path: $path,
container_path: "/tmp/path",
selinux_relabel: true
} ]' \
"$TESTDATA"/container_redis.json > "$TESTDIR"/container.json

pod_id=$(crictl runp "$TESTDIR"/sandbox.json)
ctr_id=$(crictl create "$pod_id" "$TESTDIR"/container.json "$TESTDIR"/sandbox.json)

crictl rm "$ctr_id"

# shellcheck disable=SC2012
oldlabel=$(ls -Z "$VOLUME" | awk '{ printf $1 }')

# Label file, but not top dir. This will show us the directory was not relabeled (as expected)
chcon --reference "$TESTDIR"/container.json "$VOLUME"/file # || \

# shellcheck disable=SC2012
label=$(ls -Z "$VOLUME" | awk '{ printf $1 }')
[[ "$oldlabel" != "$label" ]]

# Recreate. Since top level is already labeled right, there won't be a relabel.
ctr_id=$(crictl create "$pod_id" "$TESTDIR"/container.json "$TESTDIR"/sandbox.json)
# shellcheck disable=SC2012
newlabel=$(ls -Z "$VOLUME" | awk '{ printf $1 }')
[[ "$label" == "$newlabel" ]]
}
4 changes: 2 additions & 2 deletions test/shm_size.bats
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ EOF
}

@test "check /dev/shm is changed" {
create_shmsize_runtime
create_runtime_with_allowed_annotation "shmsize" "io.kubernetes.cri-o.ShmSize"
start_crio
# Run base container to ensure it creates at all
pod_id=$(crictl runp <(jq '.annotations."io.kubernetes.cri-o.ShmSize" = "16Mi"' "$TESTDATA"/sandbox_config.json))
Expand All @@ -40,7 +40,7 @@ EOF
}

@test "check /dev/shm fails with incorrect values" {
create_shmsize_runtime
create_runtime_with_allowed_annotation "shmsize" "io.kubernetes.cri-o.ShmSize"
start_crio
# Ensure pod fails if /dev/shm size is negative
! crictl runp <(jq '.annotations."io.kubernetes.cri-o.ShmSize" = "-1"' "$TESTDATA"/sandbox_config.json)
Expand Down