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
152 changes: 152 additions & 0 deletions internal/config/seccomp/seccomp.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package seccomp

import (
"context"
"io/ioutil"
"path/filepath"
"strings"

"github.com/containers/common/pkg/seccomp"
"github.com/cri-o/cri-o/internal/log"
"github.com/cri-o/cri-o/server/cri/types"
json "github.com/json-iterator/go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
k8sV1 "k8s.io/api/core/v1"
)

// Config is the global seccomp configuration type
Expand Down Expand Up @@ -84,3 +91,148 @@ func (c *Config) IsDisabled() bool {
func (c *Config) Profile() *seccomp.Seccomp {
return c.profile
}

// Setup can be used to setup the seccomp profile.
func (c *Config) Setup(
ctx context.Context,
specGenerator *generate.Generator,
profileField *types.SecurityProfile,
profilePath string,
) error {
if profileField == nil {
// Path based seccomp profiles will be used with a higher priority and are
// going to be removed in future Kubernetes versions.
if err := c.setupFromPath(ctx, specGenerator, profilePath); err != nil {
return errors.Wrap(err, "from profile path")
}
} else if err := c.setupFromField(ctx, specGenerator, profileField); err != nil {
// Field based seccomp profiles are newer than the path based ones and will
// be the standard in future Kubernetes versions.
return errors.Wrap(err, "from field")
}

return nil
}

func (c *Config) setupFromPath(
ctx context.Context, specGenerator *generate.Generator, profilePath string,
) error {
log.Debugf(ctx, "Setup seccomp from profile path: %s", profilePath)

if profilePath == "" {
if !c.UseDefaultWhenEmpty() {
// running w/o seccomp, aka unconfined
specGenerator.Config.Linux.Seccomp = nil
return nil
}
// default to SeccompProfileRuntimeDefault if user sets UseDefaultWhenEmpty
profilePath = k8sV1.SeccompProfileRuntimeDefault
}

// kubelet defaults sandboxes to run as `runtime/default`, we consider the
// default profilePath as unconfined if Seccomp disabled
// https://github.com/kubernetes/kubernetes/blob/12d9183da03d86c65f9f17e3e28be3c7c18ed22a/pkg/kubelet/kuberuntime/kuberuntime_sandbox.go#L162-L163
if c.IsDisabled() {
if profilePath == k8sV1.SeccompProfileRuntimeDefault {
// running w/o seccomp, aka unconfined
specGenerator.Config.Linux.Seccomp = nil
return nil
}
if profilePath != k8sV1.SeccompProfileNameUnconfined {
return errors.New(
"seccomp is not enabled, cannot run with a profile",
)
}

log.Warnf(ctx, "Seccomp is not enabled in the kernel, running container without profile")
}

if profilePath == k8sV1.SeccompProfileNameUnconfined {
// running w/o seccomp, aka unconfined
specGenerator.Config.Linux.Seccomp = nil
return nil
}

// Load the default seccomp profile from the server if the profilePath is a
// default one
if profilePath == k8sV1.SeccompProfileRuntimeDefault || profilePath == k8sV1.DeprecatedSeccompProfileDockerDefault {
linuxSpecs, err := seccomp.LoadProfileFromConfig(
c.Profile(), specGenerator.Config,
)
if err != nil {
return errors.Wrap(err, "load default profile")
}

specGenerator.Config.Linux.Seccomp = linuxSpecs
return nil
}

// Load local seccomp profiles including their availability validation
if !strings.HasPrefix(profilePath, k8sV1.SeccompLocalhostProfileNamePrefix) {
return errors.Errorf("unknown seccomp profile path: %q", profilePath)
}

fname := strings.TrimPrefix(profilePath, k8sV1.SeccompLocalhostProfileNamePrefix)
file, err := ioutil.ReadFile(filepath.FromSlash(fname))
if err != nil {
return errors.Errorf("cannot load seccomp profile %q: %v", fname, err)
}

linuxSpecs, err := seccomp.LoadProfileFromBytes(file, specGenerator.Config)
if err != nil {
return err
}
specGenerator.Config.Linux.Seccomp = linuxSpecs
return nil
}

func (c *Config) setupFromField(
ctx context.Context,
specGenerator *generate.Generator,
profileField *types.SecurityProfile,
) error {
log.Debugf(ctx, "Setup seccomp from profile field: %+v", profileField)

if c.IsDisabled() {
if profileField.ProfileType != types.SecurityProfileTypeUnconfined {
return errors.Errorf(
"seccomp is not enabled, cannot run with a profile",
)
}
log.Warnf(ctx, "seccomp is not enabled, running without profile")
specGenerator.Config.Linux.Seccomp = nil
return nil
}

if profileField.ProfileType == types.SecurityProfileTypeUnconfined {
// running w/o seccomp, aka unconfined
specGenerator.Config.Linux.Seccomp = nil
return nil
}

if profileField.ProfileType == types.SecurityProfileTypeRuntimeDefault {
linuxSpecs, err := seccomp.LoadProfileFromConfig(
c.Profile(), specGenerator.Config,
)
if err != nil {
return errors.Wrap(err, "load default profile")
}
specGenerator.Config.Linux.Seccomp = linuxSpecs
return nil
}

// Load local seccomp profiles including their availability validation
file, err := ioutil.ReadFile(filepath.FromSlash(profileField.LocalhostRef))
if err != nil {
return errors.Wrapf(
err, "unable to load local profile %q", profileField.LocalhostRef,
)
}

linuxSpecs, err := seccomp.LoadProfileFromBytes(file, specGenerator.Config)
if err != nil {
return errors.Wrap(err, "load local profile")
}
specGenerator.Config.Linux.Seccomp = linuxSpecs
return nil
}
166 changes: 146 additions & 20 deletions internal/config/seccomp/seccomp_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package seccomp_test

import (
"context"
"io/ioutil"

containers_seccomp "github.com/containers/common/pkg/seccomp"
"github.com/cri-o/cri-o/internal/config/seccomp"
"github.com/cri-o/cri-o/server/cri/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/opencontainers/runtime-tools/generate"
k8sV1 "k8s.io/api/core/v1"
)

// The actual test suite
Expand All @@ -18,6 +22,30 @@ var _ = t.Describe("Config", func() {
Expect(sut).NotTo(BeNil())
})

writeProfileFile := func() string {
file := t.MustTempFile("")
Expect(ioutil.WriteFile(file, []byte(`{
"names": ["clone"],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 1,
"value": 2080505856,
"valueTwo": 0,
"op": "SCMP_CMP_MASKED_EQ"
}
],
"comment": "s390 parameter ordering for clone is different",
"includes": {
"arches": ["s390", "s390x"]
},
"excludes": {
"caps": ["CAP_SYS_ADMIN"]
}
}`), 0o644)).To(BeNil())
return file
}

t.Describe("Profile", func() {
It("should be the default without any load", func() {
// Given
Expand All @@ -42,26 +70,7 @@ var _ = t.Describe("Config", func() {

It("should succeed with profile", func() {
// Given
file := t.MustTempFile("")
Expect(ioutil.WriteFile(file, []byte(`{
"names": ["clone"],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 1,
"value": 2080505856,
"valueTwo": 0,
"op": "SCMP_CMP_MASKED_EQ"
}
],
"comment": "s390 parameter ordering for clone is different",
"includes": {
"arches": ["s390", "s390x"]
},
"excludes": {
"caps": ["CAP_SYS_ADMIN"]
}
}`), 0o644)).To(BeNil())
file := writeProfileFile()

// When
err := sut.LoadProfile(file)
Expand All @@ -81,4 +90,121 @@ var _ = t.Describe("Config", func() {
})
}
})

t.Describe("Setup", func() {
It("should succeed with profile from file", func() {
// Given
generator, err := generate.New("linux")
Expect(err).To(BeNil())
file := writeProfileFile()

// When
err = sut.Setup(
context.Background(),
&generator,
nil,
k8sV1.SeccompLocalhostProfileNamePrefix+file,
)

// Then
Expect(err).To(BeNil())
})

It("should succeed with profile from file and runtime default", func() {
// Given
generator, err := generate.New("linux")
Expect(err).To(BeNil())

// When
err = sut.Setup(
context.Background(),
&generator,
nil,
k8sV1.SeccompProfileRuntimeDefault,
)

// Then
Expect(err).To(BeNil())
})

It("should fail with profile from file if wrong filename", func() {
// Given
generator, err := generate.New("linux")
Expect(err).To(BeNil())

// When
err = sut.Setup(
context.Background(),
&generator,
nil,
"not-existing",
)

// Then
Expect(err).NotTo(BeNil())
})

It("should succeed with custom profile from field", func() {
// Given
generator, err := generate.New("linux")
Expect(err).To(BeNil())
field := &types.SecurityProfile{
ProfileType: types.SecurityProfileTypeRuntimeDefault,
}

// When
err = sut.Setup(
context.Background(),
&generator,
field,
"",
)

// Then
Expect(err).To(BeNil())
})

It("should succeed with custom profile from field", func() {
// Given
generator, err := generate.New("linux")
Expect(err).To(BeNil())
file := writeProfileFile()
field := &types.SecurityProfile{
ProfileType: types.SecurityProfileTypeLocalhost,
LocalhostRef: file,
}

// When
err = sut.Setup(
context.Background(),
&generator,
field,
"",
)

// Then
Expect(err).To(BeNil())
})

It("should fail with custom profile from field if not existing", func() {
// Given
generator, err := generate.New("linux")
Expect(err).To(BeNil())
field := &types.SecurityProfile{
ProfileType: types.SecurityProfileTypeLocalhost,
LocalhostRef: "not-existing",
}

// When
err = sut.Setup(
context.Background(),
&generator,
field,
"",
)

// Then
Expect(err).NotTo(BeNil())
})
})
})
Loading