From 75f55706e6df857cee9da88701f322b03bddcbd1 Mon Sep 17 00:00:00 2001 From: Simon Deziel Date: Thu, 22 Feb 2024 11:19:23 -0500 Subject: [PATCH] api: add a new extension `container_syscall_filtering_allow_deny` Commit 0c987f66b6f1c added support for the respectful config key names (`security.syscalls.allow` and `security.syscalls.deny*`) but kept support for the offensive names for backward compatibility. However, that commit did not add the `container_syscall_filtering_allow_deny` extension to `shared/version/api.go`, presumably by mistake. Now that we are dropping support for the offensively named configuration keys, use the API extension name and advertise it properly. Items changed: * doc/api-extensions: rewrite keys `from container_syscall_filtering` and update `container_syscall_filtering_allow_deny` description * shared/version/api: add `container_syscall_filtering_allow_deny` extension * lxd/instance/instancetype/instance: remove `security.syscalls.(black|white)list*` keys * lxd/instance/instance_utils: remove `security.syscalls.(black|white)list*` keys * lxd/seccomp/seccomp: remove `security.syscalls.(black|white)list*` keys and error out when liblxc doesn't support the needed feature `seccomp_allow_deny_syntax` The change in lxd/seccomp/seccomp requires the underlying liblxc to support the allowlist/denylist which is the case since https://github.com/lxc/lxc/commit/78522aa93657841d7384d0800c4acd144a81c9ad which means lxc 5.0.0 and higher. Signed-off-by: Simon Deziel --- doc/api-extensions.md | 17 +++++++--- lxd/instance/instance_utils.go | 49 ++++----------------------- lxd/instance/instancetype/instance.go | 6 ---- lxd/seccomp/seccomp.go | 41 +++++----------------- shared/version/api.go | 1 + 5 files changed, 29 insertions(+), 85 deletions(-) diff --git a/doc/api-extensions.md b/doc/api-extensions.md index 7642f78c9f09..efdd83adae04 100644 --- a/doc/api-extensions.md +++ b/doc/api-extensions.md @@ -37,13 +37,20 @@ Containers with the same priority will shutdown in parallel. It defaults to 0. A number of new syscalls related container configuration keys were introduced. -* `security.syscalls.blacklist_default` -* `security.syscalls.blacklist_compat` -* `security.syscalls.blacklist` -* `security.syscalls.whitelist` +* `security.syscalls.deny_default` +* `security.syscalls.deny_compat` +* `security.syscalls.deny` +* `security.syscalls.allow` See [Instance configuration](instance-config) for how to use them. +```{note} +Initially, those configuration keys were (accidentally) introduced with +offensive names. They have since been renamed +(`container_syscall_filtering_allow_deny_syntax`), and the old names are no +longer accepted. +``` + ## `auth_pki` This indicates support for PKI authentication mode. @@ -1274,6 +1281,8 @@ A number of new syscalls related container configuration keys were updated. * `security.syscalls.deny` * `security.syscalls.allow` +Support for the offensively named variants was removed. + ## `resources_gpu_mdev` Expose available mediated device profiles and devices in `/1.0/resources`. diff --git a/lxd/instance/instance_utils.go b/lxd/instance/instance_utils.go index a00fcd03c6db..5d4d5973a206 100644 --- a/lxd/instance/instance_utils.go +++ b/lxd/instance/instance_utils.go @@ -50,24 +50,6 @@ var Load func(s *state.State, args db.InstanceArgs, p api.Project) (Instance, er // Returns a revert fail function that can be used to undo this function if a subsequent step fails. var Create func(s *state.State, args db.InstanceArgs, p api.Project) (Instance, revert.Hook, error) -func exclusiveConfigKeys(key1 string, key2 string, config map[string]string) (val string, ok bool, err error) { - if config[key1] != "" && config[key2] != "" { - return "", false, fmt.Errorf("Mutually exclusive keys %s and %s are set", key1, key2) - } - - _, ok = config[key1] - if ok { - return "", false, nil - } - - _, ok = config[key2] - if ok { - return "", false, nil - } - - return "", false, nil -} - // ValidConfig validates an instance's config. func ValidConfig(sysOS *sys.OS, config map[string]string, expanded bool, instanceType instancetype.Type) error { if config == nil { @@ -90,29 +72,10 @@ func ValidConfig(sysOS *sys.OS, config map[string]string, expanded bool, instanc } _, rawSeccomp := config["raw.seccomp"] - _, isAllow, err := exclusiveConfigKeys("security.syscalls.allow", "security.syscalls.whitelist", config) - if err != nil { - return err - } - - _, isDeny, err := exclusiveConfigKeys("security.syscalls.deny", "security.syscalls.blacklist", config) - if err != nil { - return err - } - - val, _, err := exclusiveConfigKeys("security.syscalls.deny_default", "security.syscalls.blacklist_default", config) - if err != nil { - return err - } - - isDenyDefault := shared.IsTrue(val) - - val, _, err = exclusiveConfigKeys("security.syscalls.deny_compat", "security.syscalls.blacklist_compat", config) - if err != nil { - return err - } - - isDenyCompat := shared.IsTrue(val) + _, isAllow := config["security.syscalls.allow"] + _, isDeny := config["security.syscalls.deny"] + isDenyDefault := shared.IsTrue(config["security.syscalls.deny_default"]) + isDenyCompat := shared.IsTrue(config["security.syscalls.deny_compat"]) if rawSeccomp && (isAllow || isDeny || isDenyDefault || isDenyCompat) { return fmt.Errorf("raw.seccomp is mutually exclusive with security.syscalls*") @@ -122,7 +85,7 @@ func ValidConfig(sysOS *sys.OS, config map[string]string, expanded bool, instanc return fmt.Errorf("security.syscalls.allow is mutually exclusive with security.syscalls.deny*") } - _, err = seccomp.SyscallInterceptMountFilter(config) + _, err := seccomp.SyscallInterceptMountFilter(config) if err != nil { return err } @@ -166,7 +129,7 @@ func validConfigKey(os *sys.OS, key string, value string, instanceType instancet return lxcValidConfig(value) } - if key == "security.syscalls.deny_compat" || key == "security.syscalls.blacklist_compat" { + if key == "security.syscalls.deny_compat" { for _, arch := range os.Architectures { if arch == osarch.ARCH_64BIT_INTEL_X86 || arch == osarch.ARCH_64BIT_ARMV8_LITTLE_ENDIAN || diff --git a/lxd/instance/instancetype/instance.go b/lxd/instance/instancetype/instance.go index 1cace42ac7cf..31ba8f434d47 100644 --- a/lxd/instance/instancetype/instance.go +++ b/lxd/instance/instancetype/instance.go @@ -732,10 +732,6 @@ var InstanceConfigKeysContainer = map[string]func(value string) error{ // shortdesc: List of syscalls to allow "security.syscalls.allow": validate.IsAny, - "security.syscalls.blacklist_default": validate.Optional(validate.IsBool), - "security.syscalls.blacklist_compat": validate.Optional(validate.IsBool), - "security.syscalls.blacklist": validate.IsAny, - // lxdmeta:generate(entities=instance; group=security; key=security.syscalls.deny_default) // // --- @@ -865,8 +861,6 @@ var InstanceConfigKeysContainer = map[string]func(value string) error{ // shortdesc: Whether to handle the `sysinfo` system call "security.syscalls.intercept.sysinfo": validate.Optional(validate.IsBool), - "security.syscalls.whitelist": validate.IsAny, - // lxdmeta:generate(entities=instance; group=volatile; key=volatile.last_state.idmap) // // --- diff --git a/lxd/seccomp/seccomp.go b/lxd/seccomp/seccomp.go index 59cb5ba9ef7b..a1a198100f62 100644 --- a/lxd/seccomp/seccomp.go +++ b/lxd/seccomp/seccomp.go @@ -636,8 +636,6 @@ func InstanceNeedsPolicy(c Instance) bool { "raw.seccomp", "security.syscalls.allow", "security.syscalls.deny", - "security.syscalls.whitelist", - "security.syscalls.blacklist", } for _, k := range keys { @@ -650,7 +648,6 @@ func InstanceNeedsPolicy(c Instance) bool { // Check for boolean keys that default to false keys = []string{ "security.syscalls.deny_compat", - "security.syscalls.blacklist_compat", "security.syscalls.intercept.mknod", "security.syscalls.intercept.sched_setscheduler", "security.syscalls.intercept.setxattr", @@ -667,10 +664,6 @@ func InstanceNeedsPolicy(c Instance) bool { // Check for boolean keys that default to true value, ok := config["security.syscalls.deny_default"] - if !ok { - value, ok = config["security.syscalls.blacklist_default"] - } - if !ok || shared.IsTrue(value) { return true } @@ -744,30 +737,22 @@ func seccompGetPolicyContent(s *state.State, c Instance) (string, error) { // Policy header policy := seccompHeader allowlist := config["security.syscalls.allow"] - if allowlist == "" { - allowlist = config["security.syscalls.whitelist"] - } if allowlist != "" { - if s.OS.LXCFeatures["seccomp_allow_deny_syntax"] { - policy += "allowlist\n[all]\n" - } else { - policy += "whitelist\n[all]\n" + if !s.OS.LXCFeatures["seccomp_allow_deny_syntax"] { + return "", fmt.Errorf("Unable to configure allowlist, liblxc is does not support: %q", "seccomp_allow_deny_syntax") } + policy += "allowlist\n[all]\n" policy += allowlist } else { - if s.OS.LXCFeatures["seccomp_allow_deny_syntax"] { - policy += "denylist\n[all]\n" - } else { - policy += "blacklist\n[all]\n" + if !s.OS.LXCFeatures["seccomp_allow_deny_syntax"] { + return "", fmt.Errorf("Unable to configure denylist, liblxc is does not support: %q", "seccomp_allow_deny_syntax") } - defaultFlag, ok := config["security.syscalls.deny_default"] - if !ok { - defaultFlag, ok = config["security.syscalls.blacklist_default"] - } + policy += "denylist\n[all]\n" + defaultFlag, ok := config["security.syscalls.deny_default"] if !ok || shared.IsTrue(defaultFlag) { policy += defaultSeccompPolicy } @@ -819,11 +804,7 @@ func seccompGetPolicyContent(s *state.State, c Instance) (string, error) { } // Additional deny entries - compat, ok := config["security.syscalls.deny_compat"] - if !ok { - compat = config["security.syscalls.blacklist_compat"] - } - + compat := config["security.syscalls.deny_compat"] if shared.IsTrue(compat) { arch, err := osarch.ArchitectureName(c.Architecture()) if err != nil { @@ -833,11 +814,7 @@ func seccompGetPolicyContent(s *state.State, c Instance) (string, error) { policy += fmt.Sprintf(compatBlockingPolicy, arch) } - denylist, ok := config["security.syscalls.deny"] - if !ok { - denylist = config["security.syscalls.blacklist"] - } - + denylist := config["security.syscalls.deny"] if denylist != "" { policy += denylist } diff --git a/shared/version/api.go b/shared/version/api.go index 2482febb63e6..5cc3d0a57b7e 100644 --- a/shared/version/api.go +++ b/shared/version/api.go @@ -398,6 +398,7 @@ var APIExtensions = []string{ "import_instance_devices", "instances_uefi_vars", "instances_migration_stateful", + "container_syscall_filtering_allow_deny_syntax", } // APIExtensionsCount returns the number of available API extensions.