Skip to content

Commit e3de08f

Browse files
committed
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 Signed-off-by: Alban Crequy <albancrequy@microsoft.com>
1 parent 9524366 commit e3de08f

File tree

4 files changed

+68
-5
lines changed

4 files changed

+68
-5
lines changed

libcontainer/configs/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type IDMap struct {
3333
type Seccomp struct {
3434
DefaultAction Action `json:"default_action"`
3535
Architectures []string `json:"architectures"`
36+
Flags []string `json:"flags"`
3637
Syscalls []*Syscall `json:"syscalls"`
3738
DefaultErrnoRet *uint `json:"default_errno_ret"`
3839
ListenerPath string `json:"listener_path,omitempty"`

libcontainer/seccomp/seccomp_linux.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,29 @@ func InitSeccomp(config *configs.Seccomp) (int, error) {
8686
}
8787
}
8888

89+
// Add extra flags
90+
for _, flag := range config.Flags {
91+
switch flag {
92+
case "SECCOMP_FILTER_FLAG_TSYNC":
93+
// libseccomp-golang always use filterAttrTsync when
94+
// possible so all goroutines will receive the same
95+
// rules, so there is nothing to do. It does not make
96+
// sense to apply the seccomp filter on only one
97+
// thread; other threads will be terminated after exec
98+
// anyway.
99+
case "SECCOMP_FILTER_FLAG_LOG":
100+
if err := filter.SetLogBit(true); err != nil {
101+
return -1, fmt.Errorf("error adding log flag to seccomp filter: %w", err)
102+
}
103+
case "SECCOMP_FILTER_FLAG_SPEC_ALLOW":
104+
if err := filter.SetSSB(true); err != nil {
105+
return -1, fmt.Errorf("error adding SSB flag to seccomp filter: %w", err)
106+
}
107+
default:
108+
return -1, fmt.Errorf("seccomp flags %q not yet supported by runc", flag)
109+
}
110+
}
111+
89112
// Unset no new privs bit
90113
if err := filter.SetNoNewPrivsBit(false); err != nil {
91114
return -1, fmt.Errorf("error setting no new privileges: %w", err)

libcontainer/specconv/spec_linux.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,14 +1016,22 @@ func SetupSeccomp(config *specs.LinuxSeccomp) (*configs.Seccomp, error) {
10161016
return nil, nil
10171017
}
10181018

1019-
// We don't currently support seccomp flags.
1020-
if len(config.Flags) != 0 {
1021-
return nil, errors.New("seccomp flags are not yet supported by runc")
1022-
}
1023-
10241019
newConfig := new(configs.Seccomp)
10251020
newConfig.Syscalls = []*configs.Syscall{}
10261021

1022+
// The list of flags defined in runtime-spec is a subset of the flags
1023+
// in the seccomp() syscall
1024+
for _, flag := range config.Flags {
1025+
switch flag {
1026+
case "SECCOMP_FILTER_FLAG_TSYNC":
1027+
// Tsync can be silently ignored
1028+
case "SECCOMP_FILTER_FLAG_LOG", "SECCOMP_FILTER_FLAG_SPEC_ALLOW":
1029+
newConfig.Flags = append(newConfig.Flags, string(flag))
1030+
default:
1031+
return nil, fmt.Errorf("seccomp flags %q not yet supported by runc", flag)
1032+
}
1033+
}
1034+
10271035
if len(config.Architectures) > 0 {
10281036
newConfig.Architectures = []string{}
10291037
for _, arch := range config.Architectures {

tests/integration/seccomp.bats

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,37 @@ function teardown() {
6666
[[ "$output" == *"Network is down"* ]]
6767
}
6868

69+
@test "runc run [seccomp] (SECCOMP_FILTER_FLAG_*)" {
70+
# Linux 4.14: SECCOMP_FILTER_FLAG_LOG
71+
# Linux 4.17: SECCOMP_FILTER_FLAG_SPEC_ALLOW
72+
requires_kernel 4.17
73+
SECCOMP_FILTER_FLAGS=(
74+
'' # no flag
75+
'"SECCOMP_FILTER_FLAG_LOG"'
76+
'"SECCOMP_FILTER_FLAG_SPEC_ALLOW"'
77+
'"SECCOMP_FILTER_FLAG_TSYNC"'
78+
'"SECCOMP_FILTER_FLAG_LOG","SECCOMP_FILTER_FLAG_SPEC_ALLOW"'
79+
'"SECCOMP_FILTER_FLAG_LOG","SECCOMP_FILTER_FLAG_TSYNC"'
80+
'"SECCOMP_FILTER_FLAG_SPEC_ALLOW","SECCOMP_FILTER_FLAG_TSYNC"'
81+
'"SECCOMP_FILTER_FLAG_LOG","SECCOMP_FILTER_FLAG_SPEC_ALLOW","SECCOMP_FILTER_FLAG_TSYNC"'
82+
)
83+
for flags in "${SECCOMP_FILTER_FLAGS[@]}"; do
84+
update_config ' .process.args = ["/bin/sh", "-c", "mkdir /dev/shm/foo"]
85+
| .process.noNewPrivileges = false
86+
| .linux.seccomp = {
87+
"defaultAction":"SCMP_ACT_ALLOW",
88+
"architectures":["SCMP_ARCH_X86","SCMP_ARCH_X32"],
89+
"flags":['"${flags}"'],
90+
"syscalls":[{"names":["mkdir"], "action":"SCMP_ACT_ERRNO"}]
91+
}'
92+
93+
# This test checks that the log flag is accepted but does not check
94+
runc run test_busybox
95+
[ "$status" -ne 0 ]
96+
[[ "$output" == *"mkdir:"*"/dev/shm/foo"*"Operation not permitted"* ]]
97+
done
98+
}
99+
69100
@test "runc run [seccomp] (SCMP_ACT_KILL)" {
70101
update_config ' .process.args = ["/bin/sh", "-c", "mkdir /dev/shm/foo"]
71102
| .process.noNewPrivileges = false

0 commit comments

Comments
 (0)