Skip to content

Commit

Permalink
api: add a new extension container_syscall_filtering_allow_deny
Browse files Browse the repository at this point in the history
Commit 0c987f6 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
lxc/lxc@78522aa
which means lxc 5.0.0 and higher.

Signed-off-by: Simon Deziel <[email protected]>
  • Loading branch information
simondeziel committed Feb 26, 2024
1 parent 0ff71ae commit 75f5570
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 85 deletions.
17 changes: 13 additions & 4 deletions doc/api-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` <!-- wokeignore:rule=blacklist -->
* `security.syscalls.blacklist_compat` <!-- wokeignore:rule=blacklist -->
* `security.syscalls.blacklist` <!-- wokeignore:rule=blacklist -->
* `security.syscalls.whitelist` <!-- wokeignore:rule=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.
Expand Down Expand Up @@ -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`.
Expand Down
49 changes: 6 additions & 43 deletions lxd/instance/instance_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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*")
Expand All @@ -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
}
Expand Down Expand Up @@ -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 ||
Expand Down
6 changes: 0 additions & 6 deletions lxd/instance/instancetype/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
//
// ---
Expand Down Expand Up @@ -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)
//
// ---
Expand Down
41 changes: 9 additions & 32 deletions lxd/seccomp/seccomp.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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",
Expand All @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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
}
Expand Down
1 change: 1 addition & 0 deletions shared/version/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 75f5570

Please sign in to comment.