mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
seccomp: add support for flags
List of seccomp flags defined in runtime-spec: * SECCOMP_FILTER_FLAG_TSYNC * SECCOMP_FILTER_FLAG_LOG * SECCOMP_FILTER_FLAG_SPEC_ALLOW Note that runc does not apply SECCOMP_FILTER_FLAG_TSYNC. It does not make sense to apply the seccomp filter on only one thread; other threads will be terminated after exec anyway. See similar commit in crun: https://github.com/containers/crun/commit/fefabffa2816ea343068ed036a86944393db189a Note that SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV (introduced by https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/commit/?id=c2aa2dfef243 in Linux 5.19-rc1) is not added yet because Linux 5.19 is not released yet. Signed-off-by: Alban Crequy <albancrequy@microsoft.com>
This commit is contained in:
@@ -31,12 +31,13 @@ type IDMap struct {
|
|||||||
// for syscalls. Additional architectures can be added by specifying them in
|
// for syscalls. Additional architectures can be added by specifying them in
|
||||||
// Architectures.
|
// Architectures.
|
||||||
type Seccomp struct {
|
type Seccomp struct {
|
||||||
DefaultAction Action `json:"default_action"`
|
DefaultAction Action `json:"default_action"`
|
||||||
Architectures []string `json:"architectures"`
|
Architectures []string `json:"architectures"`
|
||||||
Syscalls []*Syscall `json:"syscalls"`
|
Flags []specs.LinuxSeccompFlag `json:"flags"`
|
||||||
DefaultErrnoRet *uint `json:"default_errno_ret"`
|
Syscalls []*Syscall `json:"syscalls"`
|
||||||
ListenerPath string `json:"listener_path,omitempty"`
|
DefaultErrnoRet *uint `json:"default_errno_ret"`
|
||||||
ListenerMetadata string `json:"listener_metadata,omitempty"`
|
ListenerPath string `json:"listener_path,omitempty"`
|
||||||
|
ListenerMetadata string `json:"listener_metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Action is taken upon rule match in Seccomp
|
// Action is taken upon rule match in Seccomp
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
"github.com/opencontainers/runc/libcontainer/seccomp/patchbpf"
|
"github.com/opencontainers/runc/libcontainer/seccomp/patchbpf"
|
||||||
|
"github.com/opencontainers/runtime-spec/specs-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -86,6 +87,29 @@ func InitSeccomp(config *configs.Seccomp) (int, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add extra flags
|
||||||
|
for _, flag := range config.Flags {
|
||||||
|
switch flag {
|
||||||
|
case "SECCOMP_FILTER_FLAG_TSYNC":
|
||||||
|
// libseccomp-golang always use filterAttrTsync when
|
||||||
|
// possible so all goroutines will receive the same
|
||||||
|
// rules, so there is nothing to do. It does not make
|
||||||
|
// sense to apply the seccomp filter on only one
|
||||||
|
// thread; other threads will be terminated after exec
|
||||||
|
// anyway.
|
||||||
|
case specs.LinuxSeccompFlagLog:
|
||||||
|
if err := filter.SetLogBit(true); err != nil {
|
||||||
|
return -1, fmt.Errorf("error adding log flag to seccomp filter: %w", err)
|
||||||
|
}
|
||||||
|
case specs.LinuxSeccompFlagSpecAllow:
|
||||||
|
if err := filter.SetSSB(true); err != nil {
|
||||||
|
return -1, fmt.Errorf("error adding SSB flag to seccomp filter: %w", err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return -1, fmt.Errorf("seccomp flags %q not yet supported by runc", flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Unset no new privs bit
|
// Unset no new privs bit
|
||||||
if err := filter.SetNoNewPrivsBit(false); err != nil {
|
if err := filter.SetNoNewPrivsBit(false); err != nil {
|
||||||
return -1, fmt.Errorf("error setting no new privileges: %w", err)
|
return -1, fmt.Errorf("error setting no new privileges: %w", err)
|
||||||
|
|||||||
@@ -1016,14 +1016,22 @@ func SetupSeccomp(config *specs.LinuxSeccomp) (*configs.Seccomp, error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't currently support seccomp flags.
|
|
||||||
if len(config.Flags) != 0 {
|
|
||||||
return nil, errors.New("seccomp flags are not yet supported by runc")
|
|
||||||
}
|
|
||||||
|
|
||||||
newConfig := new(configs.Seccomp)
|
newConfig := new(configs.Seccomp)
|
||||||
newConfig.Syscalls = []*configs.Syscall{}
|
newConfig.Syscalls = []*configs.Syscall{}
|
||||||
|
|
||||||
|
// The list of flags defined in runtime-spec is a subset of the flags
|
||||||
|
// in the seccomp() syscall
|
||||||
|
for _, flag := range config.Flags {
|
||||||
|
switch flag {
|
||||||
|
case "SECCOMP_FILTER_FLAG_TSYNC":
|
||||||
|
// Tsync can be silently ignored
|
||||||
|
case specs.LinuxSeccompFlagLog, specs.LinuxSeccompFlagSpecAllow:
|
||||||
|
newConfig.Flags = append(newConfig.Flags, flag)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("seccomp flag %q not yet supported by runc", flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(config.Architectures) > 0 {
|
if len(config.Architectures) > 0 {
|
||||||
newConfig.Architectures = []string{}
|
newConfig.Architectures = []string{}
|
||||||
for _, arch := range config.Architectures {
|
for _, arch := range config.Architectures {
|
||||||
|
|||||||
@@ -66,6 +66,38 @@ function teardown() {
|
|||||||
[[ "$output" == *"Network is down"* ]]
|
[[ "$output" == *"Network is down"* ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "runc run [seccomp] (SECCOMP_FILTER_FLAG_*)" {
|
||||||
|
# Linux 4.14: SECCOMP_FILTER_FLAG_LOG
|
||||||
|
# Linux 4.17: SECCOMP_FILTER_FLAG_SPEC_ALLOW
|
||||||
|
requires_kernel 4.17
|
||||||
|
SECCOMP_FILTER_FLAGS=(
|
||||||
|
'' # no flag
|
||||||
|
'"SECCOMP_FILTER_FLAG_LOG"'
|
||||||
|
'"SECCOMP_FILTER_FLAG_SPEC_ALLOW"'
|
||||||
|
'"SECCOMP_FILTER_FLAG_TSYNC"'
|
||||||
|
'"SECCOMP_FILTER_FLAG_LOG","SECCOMP_FILTER_FLAG_SPEC_ALLOW"'
|
||||||
|
'"SECCOMP_FILTER_FLAG_LOG","SECCOMP_FILTER_FLAG_TSYNC"'
|
||||||
|
'"SECCOMP_FILTER_FLAG_SPEC_ALLOW","SECCOMP_FILTER_FLAG_TSYNC"'
|
||||||
|
'"SECCOMP_FILTER_FLAG_LOG","SECCOMP_FILTER_FLAG_SPEC_ALLOW","SECCOMP_FILTER_FLAG_TSYNC"'
|
||||||
|
)
|
||||||
|
for flags in "${SECCOMP_FILTER_FLAGS[@]}"; do
|
||||||
|
update_config ' .process.args = ["/bin/sh", "-c", "mkdir /dev/shm/foo"]
|
||||||
|
| .process.noNewPrivileges = false
|
||||||
|
| .linux.seccomp = {
|
||||||
|
"defaultAction":"SCMP_ACT_ALLOW",
|
||||||
|
"architectures":["SCMP_ARCH_X86","SCMP_ARCH_X32","SCMP_ARCH_X86_64","SCMP_ARCH_AARCH64","SCMP_ARCH_ARM"],
|
||||||
|
"flags":['"${flags}"'],
|
||||||
|
"syscalls":[{"names":["mkdir"], "action":"SCMP_ACT_ERRNO"}]
|
||||||
|
}'
|
||||||
|
|
||||||
|
# This test checks that the flags are accepted without errors but does
|
||||||
|
# not check they are effectively applied
|
||||||
|
runc run test_busybox
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
[[ "$output" == *"mkdir:"*"/dev/shm/foo"*"Operation not permitted"* ]]
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
@test "runc run [seccomp] (SCMP_ACT_KILL)" {
|
@test "runc run [seccomp] (SCMP_ACT_KILL)" {
|
||||||
update_config ' .process.args = ["/bin/sh", "-c", "mkdir /dev/shm/foo"]
|
update_config ' .process.args = ["/bin/sh", "-c", "mkdir /dev/shm/foo"]
|
||||||
| .process.noNewPrivileges = false
|
| .process.noNewPrivileges = false
|
||||||
|
|||||||
Reference in New Issue
Block a user