runc features: add seccomp filter flags

Amend runc features to print seccomp flags. Two set of flags are added:
 * known flags are those that this version of runc is aware of;
 * supported flags are those that can be set; normally, this is the same
   set as known flags, but due to older version of kernel and/or
   libseccomp, some known flags might be unsupported.

This commit also consolidates three different switch statements dealing
with flags into one, in func setFlag. A note is added to this function
telling what else to look for when adding new flags.

Unfortunately, it also adds a list of known flags, that should be
kept in sync with the switch statement.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
Kir Kolyshkin
2022-09-02 12:20:54 -07:00
parent ab8480893e
commit 076745a40f
7 changed files with 127 additions and 31 deletions
+64 -20
View File
@@ -87,27 +87,10 @@ func InitSeccomp(config *configs.Seccomp) (int, error) {
}
}
// Add extra flags
// 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)
}
// NOTE when adding more flags, make sure to also modify filterFlags in patchbpf.
default:
return -1, fmt.Errorf("seccomp flags %q not yet supported by runc", flag)
if err := setFlag(filter, flag); err != nil {
return -1, err
}
}
@@ -149,6 +132,67 @@ func InitSeccomp(config *configs.Seccomp) (int, error) {
return seccompFd, nil
}
type unknownFlagError struct {
flag specs.LinuxSeccompFlag
}
func (e *unknownFlagError) Error() string {
return "seccomp flag " + string(e.flag) + " is not known to runc"
}
func setFlag(filter *libseccomp.ScmpFilter, flag specs.LinuxSeccompFlag) error {
switch flag {
case flagTsync:
// 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.
return nil
case specs.LinuxSeccompFlagLog:
if err := filter.SetLogBit(true); err != nil {
return fmt.Errorf("error adding log flag to seccomp filter: %w", err)
}
return nil
case specs.LinuxSeccompFlagSpecAllow:
if err := filter.SetSSB(true); err != nil {
return fmt.Errorf("error adding SSB flag to seccomp filter: %w", err)
}
return nil
}
// NOTE when adding more flags above, do not forget to also:
// - add new flags to `flags` slice in config.go;
// - add new flags to tests/integration/seccomp.bats flags test;
// - modify func filterFlags in patchbpf/ accordingly.
return &unknownFlagError{flag: flag}
}
// FlagSupported checks if the flag is known to runc and supported by
// currently used libseccomp and kernel (i.e. it can be set).
func FlagSupported(flag specs.LinuxSeccompFlag) error {
filter := &libseccomp.ScmpFilter{}
err := setFlag(filter, flag)
// For flags we don't know, setFlag returns unknownFlagError.
var uf *unknownFlagError
if errors.As(err, &uf) {
return err
}
// For flags that are known to runc and libseccomp-golang but can not
// be applied because either libseccomp or the kernel is too old,
// seccomp.VersionError is returned.
var verErr *libseccomp.VersionError
if errors.As(err, &verErr) {
// Not supported by libseccomp or the kernel.
return err
}
// All other flags are known and supported.
return nil
}
// Convert Libcontainer Action to Libseccomp ScmpAction
func getAction(act configs.Action, errnoRet *uint) (libseccomp.ScmpAction, error) {
switch act {