seccomp: Seccomp: embed oci-spec LinuxSeccomp, add support for seccomp flags

This patch, similar to d92739713c, embeds the
`LinuxSeccomp` type of the runtime-spec, so that we can support all options
provided by the spec, and decorates it with our own fields.

With this, profiles can make use of the recently added "Flags" field, to
specify flags that must be passed to seccomp(2) when installing the filter.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2021-07-16 17:55:04 +02:00
parent bfd4b64600
commit 0ef7e727d2
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
4 changed files with 32 additions and 22 deletions

View File

@ -740,8 +740,10 @@ func DefaultProfile() *Seccomp {
}
return &Seccomp{
DefaultAction: specs.ActErrno,
ArchMap: arches(),
Syscalls: syscalls,
LinuxSeccomp: specs.LinuxSeccomp{
DefaultAction: specs.ActErrno,
},
ArchMap: arches(),
Syscalls: syscalls,
}
}

View File

@ -10,15 +10,12 @@ import (
)
// Seccomp represents the config for a seccomp profile for syscall restriction.
// It is used to marshal/unmarshal the JSON profiles as accepted by docker, and
// extends the runtime-spec's specs.LinuxSeccomp, overriding some fields to
// provide the ability to define conditional rules based on the host's kernel
// version, architecture, and the container's capabilities.
type Seccomp struct {
DefaultAction specs.LinuxSeccompAction `json:"defaultAction"`
DefaultErrnoRet *uint `json:"defaultErrnoRet,omitempty"`
ListenerPath string `json:"listenerPath,omitempty"`
ListenerMetadata string `json:"listenerMetadata,omitempty"`
// Architectures is kept to maintain backward compatibility with the old
// seccomp profile.
Architectures []specs.Arch `json:"architectures,omitempty"`
specs.LinuxSeccomp
// ArchMap contains a list of Architectures and Sub-architectures for the
// profile. When generating the profile, this list is expanded to a

View File

@ -82,18 +82,22 @@ func setupSeccomp(config *Seccomp, rs *specs.Spec) (*specs.LinuxSeccomp, error)
return nil, nil
}
newConfig := &specs.LinuxSeccomp{}
if len(config.Architectures) != 0 && len(config.ArchMap) != 0 {
return nil, errors.New("both 'architectures' and 'archMap' are specified in the seccomp profile, use either 'architectures' or 'archMap'")
}
// if config.Architectures == 0 then libseccomp will figure out the architecture to use
if len(config.Architectures) != 0 {
newConfig.Architectures = config.Architectures
if len(config.LinuxSeccomp.Syscalls) != 0 {
// The Seccomp type overrides the LinuxSeccomp.Syscalls field,
// so 'this should never happen' when loaded from JSON, but could
// happen if someone constructs the Config from source.
return nil, errors.New("the LinuxSeccomp.Syscalls field should be empty")
}
arch := goToNative[runtime.GOARCH]
var (
// Copy all common / standard properties to the output profile
newConfig = &config.LinuxSeccomp
arch = goToNative[runtime.GOARCH]
)
if seccompArch, ok := nativeToSeccomp[arch]; ok {
for _, a := range config.ArchMap {
if a.Arch == seccompArch {
@ -104,11 +108,6 @@ func setupSeccomp(config *Seccomp, rs *specs.Spec) (*specs.LinuxSeccomp, error)
}
}
newConfig.DefaultAction = config.DefaultAction
newConfig.DefaultErrnoRet = config.DefaultErrnoRet
newConfig.ListenerPath = config.ListenerPath
newConfig.ListenerMetadata = config.ListenerMetadata
Loop:
// Convert Syscall to OCI runtimes-spec specs.LinuxSyscall after filtering them.
for _, call := range config.Syscalls {

View File

@ -100,6 +100,18 @@ func TestLoadProfileWithListenerPath(t *testing.T) {
assert.DeepEqual(t, expected, *p)
}
func TestLoadProfileWithFlag(t *testing.T) {
profile := `{"defaultAction": "SCMP_ACT_ERRNO", "flags": ["SECCOMP_FILTER_FLAG_SPEC_ALLOW", "SECCOMP_FILTER_FLAG_LOG"]}`
expected := specs.LinuxSeccomp{
DefaultAction: specs.ActErrno,
Flags: []specs.LinuxSeccompFlag{"SECCOMP_FILTER_FLAG_SPEC_ALLOW", "SECCOMP_FILTER_FLAG_LOG"},
}
rs := createSpec()
p, err := LoadProfile(profile, &rs)
assert.NilError(t, err)
assert.DeepEqual(t, expected, *p)
}
// TestLoadProfileValidation tests that invalid profiles produce the correct error.
func TestLoadProfileValidation(t *testing.T) {
tests := []struct {