[lxc-devel] [lxd/master] config key & terminology fixes
brauner on Github
lxc-bot at linuxcontainers.org
Fri Jul 3 13:36:14 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200703/7a081431/attachment.bin>
-------------- next part --------------
From 9b09647b1f06851cc8af566ac7c7851e66cb3302 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 3 Jul 2020 14:52:11 +0200
Subject: [PATCH 1/2] instance: update terminology I
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
lxd/instance/instance_utils.go | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/lxd/instance/instance_utils.go b/lxd/instance/instance_utils.go
index e9837df99b..3067478441 100644
--- a/lxd/instance/instance_utils.go
+++ b/lxd/instance/instance_utils.go
@@ -124,16 +124,16 @@ func ValidConfig(sysOS *sys.OS, config map[string]string, profile bool, expanded
}
_, rawSeccomp := config["raw.seccomp"]
- _, whitelist := config["security.syscalls.whitelist"]
- _, blacklist := config["security.syscalls.blacklist"]
- blacklistDefault := shared.IsTrue(config["security.syscalls.blacklist_default"])
- blacklistCompat := shared.IsTrue(config["security.syscalls.blacklist_compat"])
+ _, isAllow := config["security.syscalls.whitelist"]
+ _, isDeny := config["security.syscalls.blacklist"]
+ isDenyDefault := shared.IsTrue(config["security.syscalls.blacklist_default"])
+ isDenyCompat := shared.IsTrue(config["security.syscalls.blacklist_compat"])
- if rawSeccomp && (whitelist || blacklist || blacklistDefault || blacklistCompat) {
+ if rawSeccomp && (isAllow || isDeny || isDenyDefault || isDenyCompat) {
return fmt.Errorf("raw.seccomp is mutually exclusive with security.syscalls*")
}
- if whitelist && (blacklist || blacklistDefault || blacklistCompat) {
+ if isAllow && (isDeny || isDenyDefault || isDenyCompat) {
return fmt.Errorf("security.syscalls.whitelist is mutually exclusive with security.syscalls.blacklist*")
}
@@ -230,7 +230,7 @@ func lxcValidConfig(rawLxc string) error {
}
}
- // Blacklist some keys
+ // block some keys
if key == "lxc.logfile" || key == "lxc.log.file" {
return fmt.Errorf("Setting lxc.logfile is not allowed")
}
From 946df3a2c4e32863b05af6c6357c3438606ef1b5 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 3 Jul 2020 15:33:13 +0200
Subject: [PATCH 2/2] instance: introduce
container_syscall_filtering_allow_deny extension
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
doc/api-extensions.md | 8 ++++++
doc/instances.md | 8 +++---
lxd/daemon.go | 1 +
lxd/instance/instance_utils.go | 51 ++++++++++++++++++++++++++++------
lxd/seccomp/seccomp.go | 45 ++++++++++++++++++++++--------
scripts/bash/lxd-client | 5 ++--
shared/instance.go | 4 +++
test/suites/basic.sh | 2 +-
8 files changed, 97 insertions(+), 27 deletions(-)
diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index ea699c5d7f..f009352b91 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -1098,3 +1098,11 @@ It introduces the new `--type` flag when creating custom storage volumes, and ac
This extension adds a new `failure_domain` field to the `PUT /1.0/cluster/<node>` API,
which can be used to set the failure domain of a node.
+
+## container\_syscall\_filtering\_allow\_deny\_syntax
+A number of new syscalls related container configuration keys were updated.
+
+ * `security.syscalls.deny_default`
+ * `security.syscalls.deny_compat`
+ * `security.syscalls.deny`
+ * `security.syscalls.allow`
diff --git a/doc/instances.md b/doc/instances.md
index 6663111ee9..ae25f602b1 100644
--- a/doc/instances.md
+++ b/doc/instances.md
@@ -81,16 +81,16 @@ security.privileged | boolean | false | no
security.protection.delete | boolean | false | yes | - | Prevents the instance from being deleted
security.protection.shift | boolean | false | yes | container | Prevents the instance's filesystem from being uid/gid shifted on startup
security.secureboot | boolean | true | no | virtual-machine | Controls whether UEFI secure boot is enabled with the default Microsoft keys
-security.syscalls.blacklist | string | - | no | container | A '\n' separated list of syscalls to blacklist
-security.syscalls.blacklist\_compat | boolean | false | no | container | On x86\_64 this enables blocking of compat\_\* syscalls, it is a no-op on other arches
-security.syscalls.blacklist\_default | boolean | true | no | container | Enables the default syscall blacklist
+security.syscalls.deny | string | - | no | container | A '\n' separated list of syscalls to deny
+security.syscalls.deny\_compat | boolean | false | no | container | On x86\_64 this enables blocking of compat\_\* syscalls, it is a no-op on other arches
+security.syscalls.deny\_default | boolean | true | no | container | Enables the default syscall deny
security.syscalls.intercept.mknod | boolean | false | no | container | Handles the `mknod` and `mknodat` system calls (allows creation of a limited subset of char/block devices)
security.syscalls.intercept.mount | boolean | false | no | container | Handles the `mount` system call
security.syscalls.intercept.mount.allowed | string | - | yes | container | Specify a comma-separated list of filesystems that are safe to mount for processes inside the instance
security.syscalls.intercept.mount.fuse | string | - | yes | container | Whether to redirect mounts of a given filesystem to their fuse implemenation (e.g. ext4=fuse2fs)
security.syscalls.intercept.mount.shift | boolean | false | yes | container | Whether to mount shiftfs on top of filesystems handled through mount syscall interception
security.syscalls.intercept.setxattr | boolean | false | no | container | Handles the `setxattr` system call (allows setting a limited subset of restricted extended attributes)
-security.syscalls.whitelist | string | - | no | container | A '\n' separated list of syscalls to whitelist (mutually exclusive with security.syscalls.blacklist\*)
+security.syscalls.allow | string | - | no | container | A '\n' separated list of syscalls to allow (mutually exclusive with security.syscalls.deny\*)
snapshots.schedule | string | - | no | - | Cron expression (`<minute> <hour> <dom> <month> <dow>`)
snapshots.schedule.stopped | bool | false | no | - | Controls whether or not stopped instances are to be snapshoted automatically
snapshots.pattern | string | snap%d | no | - | Pongo2 template string which represents the snapshot name (used for scheduled snapshots and unnamed snapshots)
diff --git a/lxd/daemon.go b/lxd/daemon.go
index 30357daddf..f04ceb58dd 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -610,6 +610,7 @@ func (d *Daemon) init() error {
"network_veth_router",
"cgroup2",
"pidfd",
+ "seccomp_allow_deny_syntax",
}
for _, extension := range lxcExtensions {
d.os.LXCFeatures[extension] = liblxc.HasApiExtension(extension)
diff --git a/lxd/instance/instance_utils.go b/lxd/instance/instance_utils.go
index 3067478441..5dd419c8b6 100644
--- a/lxd/instance/instance_utils.go
+++ b/lxd/instance/instance_utils.go
@@ -102,6 +102,24 @@ func CompareSnapshots(source Instance, target Instance) ([]Instance, []Instance,
return toSync, toDelete, nil
}
+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)
+ }
+
+ val, ok = config[key1]
+ if ok {
+ return
+ }
+
+ val, ok = config[key2]
+ if ok {
+ return
+ }
+
+ return "", false, nil
+}
+
// ValidConfig validates an instance's config.
func ValidConfig(sysOS *sys.OS, config map[string]string, profile bool, expanded bool) error {
if config == nil {
@@ -124,20 +142,37 @@ func ValidConfig(sysOS *sys.OS, config map[string]string, profile bool, expanded
}
_, rawSeccomp := config["raw.seccomp"]
- _, isAllow := config["security.syscalls.whitelist"]
- _, isDeny := config["security.syscalls.blacklist"]
- isDenyDefault := shared.IsTrue(config["security.syscalls.blacklist_default"])
- isDenyCompat := shared.IsTrue(config["security.syscalls.blacklist_compat"])
+ _, 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)
if rawSeccomp && (isAllow || isDeny || isDenyDefault || isDenyCompat) {
return fmt.Errorf("raw.seccomp is mutually exclusive with security.syscalls*")
}
if isAllow && (isDeny || isDenyDefault || isDenyCompat) {
- return fmt.Errorf("security.syscalls.whitelist is mutually exclusive with security.syscalls.blacklist*")
+ 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
}
@@ -174,7 +209,7 @@ func validConfigKey(os *sys.OS, key string, value string) error {
if key == "raw.lxc" {
return lxcValidConfig(value)
}
- if key == "security.syscalls.blacklist_compat" {
+ if key == "security.syscalls.deny_compat" || key == "security.syscalls.blacklist_compat" {
for _, arch := range os.Architectures {
if arch == osarch.ARCH_64BIT_INTEL_X86 ||
arch == osarch.ARCH_64BIT_ARMV8_LITTLE_ENDIAN ||
@@ -182,7 +217,7 @@ func validConfigKey(os *sys.OS, key string, value string) error {
return nil
}
}
- return fmt.Errorf("security.syscalls.blacklist_compat isn't supported on this architecture")
+ return fmt.Errorf("%s isn't supported on this architecture", key)
}
return nil
}
diff --git a/lxd/seccomp/seccomp.go b/lxd/seccomp/seccomp.go
index d72c97f45b..4d96eefe6e 100644
--- a/lxd/seccomp/seccomp.go
+++ b/lxd/seccomp/seccomp.go
@@ -389,6 +389,8 @@ func InstanceNeedsPolicy(c Instance) bool {
// Check for text keys
keys := []string{
"raw.seccomp",
+ "security.syscalls.allow",
+ "security.syscalls.deny",
"security.syscalls.whitelist",
"security.syscalls.blacklist",
}
@@ -402,6 +404,7 @@ 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.setxattr",
@@ -416,6 +419,7 @@ func InstanceNeedsPolicy(c Instance) bool {
// Check for boolean keys that default to true
keys = []string{
+ "security.syscalls.deny_default",
"security.syscalls.blacklist_default",
}
@@ -490,14 +494,25 @@ func seccompGetPolicyContent(s *state.State, c Instance) (string, error) {
// Policy header
policy := seccompHeader
- whitelist := config["security.syscalls.whitelist"]
- if whitelist != "" {
- policy += "whitelist\n[all]\n"
- policy += whitelist
+ allowlist := config["security.syscalls.allowlist"]
+ if allowlist != "" {
+ if s.OS.LXCFeatures["seccomp_allow_deny_syntax"] {
+ policy += "allowlist\n[all]\n"
+ } else {
+ policy += "whitelist\n[all]\n"
+ }
+ policy += allowlist
} else {
- policy += "blacklist\n"
+ if s.OS.LXCFeatures["seccomp_allow_deny_syntax"] {
+ policy += "denylist\n[all]\n"
+ } else {
+ policy += "blacklist\n[all]\n"
+ }
- defaultFlag, ok := config["security.syscalls.blacklist_default"]
+ defaultFlag, ok := config["security.syscalls.deny_default"]
+ if !ok {
+ defaultFlag, ok = config["security.syscalls.blacklist_default"]
+ }
if !ok || shared.IsTrue(defaultFlag) {
policy += defaultSeccompPolicy
}
@@ -531,12 +546,15 @@ func seccompGetPolicyContent(s *state.State, c Instance) (string, error) {
}
}
- if whitelist != "" {
+ if allowlist != "" {
return policy, nil
}
- // Additional blacklist entries
- compat := config["security.syscalls.blacklist_compat"]
+ // Additional deny entries
+ compat, ok := config["security.syscalls.deny_compat"]
+ if !ok {
+ compat, ok = config["security.syscalls.blacklist_compat"]
+ }
if shared.IsTrue(compat) {
arch, err := osarch.ArchitectureName(c.Architecture())
if err != nil {
@@ -545,9 +563,12 @@ func seccompGetPolicyContent(s *state.State, c Instance) (string, error) {
policy += fmt.Sprintf(compatBlockingPolicy, arch)
}
- blacklist := config["security.syscalls.blacklist"]
- if blacklist != "" {
- policy += blacklist
+ denylist, ok := config["security.syscalls.deny"]
+ if !ok {
+ denylist, ok = config["security.syscalls.blacklist"]
+ }
+ if denylist != "" {
+ policy += denylist
}
return policy, nil
diff --git a/scripts/bash/lxd-client b/scripts/bash/lxd-client
index 173bf03a10..37996d89b7 100644
--- a/scripts/bash/lxd-client
+++ b/scripts/bash/lxd-client
@@ -99,8 +99,9 @@ _have lxc && {
security.idmap.size security.devlxd security.devlxd.images \
security.nesting security.privileged security.protection.delete \
security.protection.shift security.secureboot \
- security.syscalls.blacklist \
- security.syscalls.blacklist_compat security.syscalls.blacklist_default \
+ security.syscalls.allow \
+ security.syscalls.deny \
+ security.syscalls.deny_compat security.syscalls.deny_default \
security.syscalls.intercept.mknod security.syscalls.intercept.mount \
security.syscalls.intercept.mount.allowed \
security.syscalls.intercept.mount.fuse \
diff --git a/shared/instance.go b/shared/instance.go
index 3bab51df3c..953981dbe1 100644
--- a/shared/instance.go
+++ b/shared/instance.go
@@ -322,6 +322,9 @@ var KnownInstanceConfigKeys = map[string]func(value string) error{
"security.secureboot": IsBool,
+ "security.syscalls.deny_default": IsBool,
+ "security.syscalls.deny_compat": IsBool,
+ "security.syscalls.deny": IsAny,
"security.syscalls.blacklist_default": IsBool,
"security.syscalls.blacklist_compat": IsBool,
"security.syscalls.blacklist": IsAny,
@@ -331,6 +334,7 @@ var KnownInstanceConfigKeys = map[string]func(value string) error{
"security.syscalls.intercept.mount.fuse": IsAny,
"security.syscalls.intercept.mount.shift": IsBool,
"security.syscalls.intercept.setxattr": IsBool,
+ "security.syscalls.allow": IsAny,
"security.syscalls.whitelist": IsAny,
"snapshots.schedule": func(value string) error {
diff --git a/test/suites/basic.sh b/test/suites/basic.sh
index 95f7256327..f3afd39af2 100644
--- a/test/suites/basic.sh
+++ b/test/suites/basic.sh
@@ -447,7 +447,7 @@ test_basic_usage() {
init=$(lxc info lxd-seccomp-test | grep Pid | cut -f2 -d" ")
[ "$(grep Seccomp "/proc/${init}/status" | cut -f2)" -eq "2" ]
lxc stop --force lxd-seccomp-test
- lxc config set lxd-seccomp-test security.syscalls.blacklist_default false
+ lxc config set lxd-seccomp-test security.syscalls.deny_default false
lxc start lxd-seccomp-test
init=$(lxc info lxd-seccomp-test | grep Pid | cut -f2 -d" ")
[ "$(grep Seccomp "/proc/${init}/status" | cut -f2)" -eq "0" ]
More information about the lxc-devel
mailing list