[libvirt] [RFC PATCH 0/2] qemu: deny privilege elevation and spawn in seccomp

QEMU changed the behavior of -sandbox on since 2.11 and it no longer whitelists all the possible calls. Override the meaning of seccomp_sandbox = 1 in qemu.conf to block the privilege elevation set and spawn set on top of the default. Do the same by default even if no option is specified, hoping that this should be enough for everybody (TM) Sending as RFC to ask whether: * this is a sensible default * a coarse setting like this is enough or it makes sense to expose the individual sets in qemu.conf (in that case - can I reasonably promote an int setting to a list of strings?) Ján Tomko (2): Introduce QEMU_CAPS_SECCOMP_BLACKLIST qemu: deny privilege elevation and spawn in seccomp src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 10 +++++-- tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml | 1 + tests/qemuxml2argvdata/minimal-sandbox.args | 25 ++++++++++++++++ tests/qemuxml2argvdata/minimal-sandbox.xml | 34 ++++++++++++++++++++++ tests/qemuxml2argvtest.c | 3 ++ 11 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 tests/qemuxml2argvdata/minimal-sandbox.args create mode 100644 tests/qemuxml2argvdata/minimal-sandbox.xml -- 2.13.6

QEMU commit 1bd6152 changed the default behavior from whitelist to blacklist and introduced a few sets of system calls. Use the 'elevateprivileges' parameter of -sandbox as a witness of this change. https://bugzilla.redhat.com/show_bug.cgi?id=1492597 Signed-off-by: Ján Tomko <jtomko@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml | 1 + tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml | 1 + 7 files changed, 8 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index e54dde69a..a47951ebb 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -466,6 +466,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, /* 285 */ "virtio-mouse-ccw", "virtio-tablet-ccw", + "seccomp-blacklist", ); @@ -3210,6 +3211,7 @@ static struct virQEMUCapsCommandLineProps virQEMUCapsCommandLine[] = { { "machine", "loadparm", QEMU_CAPS_LOADPARM }, { "vnc", "vnc", QEMU_CAPS_VNC_MULTI_SERVERS }, { "chardev", "reconnect", QEMU_CAPS_CHARDEV_RECONNECT }, + { "sandbox", "elevateprivileges", QEMU_CAPS_SECCOMP_BLACKLIST }, }; static int diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 3f3c29f8f..f6a10941b 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -450,6 +450,7 @@ typedef enum { /* 285 */ QEMU_CAPS_DEVICE_VIRTIO_MOUSE_CCW, /* -device virtio-mouse-ccw */ QEMU_CAPS_DEVICE_VIRTIO_TABLET_CCW, /* -device virtio-tablet-ccw */ + QEMU_CAPS_SECCOMP_BLACKLIST, /* -sandbox.elevateprivileges */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml index 70a35ef50..9ef03834d 100644 --- a/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml @@ -150,6 +150,7 @@ <flag name='virtio-keyboard-ccw'/> <flag name='virtio-mouse-ccw'/> <flag name='virtio-tablet-ccw'/> + <flag name='seccomp-blacklist'/> <version>2011000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>342058</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml b/tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml index ff4829365..921e8c914 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml +++ b/tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml @@ -187,6 +187,7 @@ <flag name='isa-serial'/> <flag name='pl011'/> <flag name='dump-completed'/> + <flag name='seccomp-blacklist'/> <version>2011090</version> <kvmVersion>0</kvmVersion> <microcodeVersion>342346</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml b/tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml index ee7fb9e05..d404c830b 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml +++ b/tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml @@ -185,6 +185,7 @@ <flag name='isa-serial'/> <flag name='machine.pseries.max-cpu-compat'/> <flag name='dump-completed'/> + <flag name='seccomp-blacklist'/> <version>2011090</version> <kvmVersion>0</kvmVersion> <microcodeVersion>419215</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml index b5b6b5b3b..4d93ad768 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml @@ -150,6 +150,7 @@ <flag name='virtio-keyboard-ccw'/> <flag name='virtio-mouse-ccw'/> <flag name='virtio-tablet-ccw'/> + <flag name='seccomp-blacklist'/> <version>2011090</version> <kvmVersion>0</kvmVersion> <microcodeVersion>0</microcodeVersion> diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml index 334296e21..b0ad13009 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml @@ -225,6 +225,7 @@ <flag name='iscsi.password-secret'/> <flag name='isa-serial'/> <flag name='dump-completed'/> + <flag name='seccomp-blacklist'/> <version>2011090</version> <kvmVersion>0</kvmVersion> <microcodeVersion>390060</microcodeVersion> -- 2.13.6

If QEMU uses a seccomp blacklist (since 2.11), -sandbox on no longer tries to whitelist all the calls, but uses sets of blacklists: default (always blacklisted with -sandbox on) obsolete (defaults to deny) elevateprivileges (setuid & co, default: allow) spwan (fork & execve, default: allow) resourcecontrol (setaffinity, setscheduler, default: allow) If these are supported, default to sandbox with spawn and elevateprivileges blacklisted. https://bugzilla.redhat.com/show_bug.cgi?id=1492597 Signed-off-by: Ján Tomko <jtomko@redhat.com> --- src/qemu/qemu_command.c | 10 +++++++-- tests/qemuxml2argvdata/minimal-sandbox.args | 25 +++++++++++++++++++++ tests/qemuxml2argvdata/minimal-sandbox.xml | 34 +++++++++++++++++++++++++++++ tests/qemuxml2argvtest.c | 3 +++ 4 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 tests/qemuxml2argvdata/minimal-sandbox.args create mode 100644 tests/qemuxml2argvdata/minimal-sandbox.xml diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 89fd08b64..3388f861a 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -10211,10 +10211,16 @@ qemuBuildCommandLine(virQEMUDriverPtr driver, } if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SECCOMP_SANDBOX)) { - if (cfg->seccompSandbox == 0) + if (cfg->seccompSandbox == 0) { virCommandAddArgList(cmd, "-sandbox", "off", NULL); - else if (cfg->seccompSandbox > 0) + } else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SECCOMP_BLACKLIST) && + cfg->seccompSandbox != 0) { + virCommandAddArgList(cmd, "-sandbox", + "on,elevateprivileges=deny,spawn=deny", NULL); + /* obsolete=deny, resourcecontrol=allow */ + } else if (cfg->seccompSandbox > 0) { virCommandAddArgList(cmd, "-sandbox", "on", NULL); + } } else if (cfg->seccompSandbox > 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("QEMU does not support seccomp sandboxes")); diff --git a/tests/qemuxml2argvdata/minimal-sandbox.args b/tests/qemuxml2argvdata/minimal-sandbox.args new file mode 100644 index 000000000..285cfed70 --- /dev/null +++ b/tests/qemuxml2argvdata/minimal-sandbox.args @@ -0,0 +1,25 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-i686 \ +-name QEMUGuest1 \ +-S \ +-M pc \ +-m 214 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-nographic \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-no-acpi \ +-boot c \ +-usb \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \ +-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3 \ +-sandbox on,elevateprivileges=deny,spawn=deny diff --git a/tests/qemuxml2argvdata/minimal-sandbox.xml b/tests/qemuxml2argvdata/minimal-sandbox.xml new file mode 100644 index 000000000..9ef92f8fe --- /dev/null +++ b/tests/qemuxml2argvdata/minimal-sandbox.xml @@ -0,0 +1,34 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <title>A description of the test machine.</title> + <description> + A test of qemu's minimal configuration. + This test also tests the description and title elements. + </description> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-i686</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 308d71f72..5fb16987f 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -691,6 +691,9 @@ mymain(void) unsetenv("SDL_AUDIODRIVER"); DO_TEST("minimal", NONE); + DO_TEST("minimal-sandbox", + QEMU_CAPS_SECCOMP_SANDBOX, + QEMU_CAPS_SECCOMP_BLACKLIST); DO_TEST_PARSE_ERROR("minimal-no-memory", NONE); DO_TEST("minimal-msg-timestamp", QEMU_CAPS_MSG_TIMESTAMP); DO_TEST("machine-aliases1", NONE); -- 2.13.6

On Sat, Mar 31, 2018 at 10:15:03PM +0200, Ján Tomko wrote:
If QEMU uses a seccomp blacklist (since 2.11), -sandbox on no longer tries to whitelist all the calls, but uses sets of blacklists: default (always blacklisted with -sandbox on) obsolete (defaults to deny)
Perhaps list that anyway, so we don't rely on defaults.
elevateprivileges (setuid & co, default: allow) spwan (fork & execve, default: allow)
s/spwan/spawn/
resourcecontrol (setaffinity, setscheduler, default: allow)
I'm thinking we should blacklist resourcecontrol too perhaps, since libvirt should be applying affinity/sched params itself.
If these are supported, default to sandbox with spawn and elevateprivileges blacklisted.
https://bugzilla.redhat.com/show_bug.cgi?id=1492597
Signed-off-by: Ján Tomko <jtomko@redhat.com> --- src/qemu/qemu_command.c | 10 +++++++-- tests/qemuxml2argvdata/minimal-sandbox.args | 25 +++++++++++++++++++++ tests/qemuxml2argvdata/minimal-sandbox.xml | 34 +++++++++++++++++++++++++++++ tests/qemuxml2argvtest.c | 3 +++ 4 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 tests/qemuxml2argvdata/minimal-sandbox.args create mode 100644 tests/qemuxml2argvdata/minimal-sandbox.xml
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 89fd08b64..3388f861a 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -10211,10 +10211,16 @@ qemuBuildCommandLine(virQEMUDriverPtr driver, }
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SECCOMP_SANDBOX)) { - if (cfg->seccompSandbox == 0) + if (cfg->seccompSandbox == 0) { virCommandAddArgList(cmd, "-sandbox", "off", NULL); - else if (cfg->seccompSandbox > 0) + } else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SECCOMP_BLACKLIST) && + cfg->seccompSandbox != 0) {
Ok this relies on fact that seccompSandbox defaults to '-1' if not present in the config file, or can be set to 1 by the user.
+ virCommandAddArgList(cmd, "-sandbox", + "on,elevateprivileges=deny,spawn=deny", NULL);
+ /* obsolete=deny, resourcecontrol=allow */
Yes, I'd suggest we add these too
+ } else if (cfg->seccompSandbox > 0) {
So this is unreachable with new qemu
virCommandAddArgList(cmd, "-sandbox", "on", NULL); + } } else if (cfg->seccompSandbox > 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("QEMU does not support seccomp sandboxes")); diff --git a/tests/qemuxml2argvdata/minimal-sandbox.args b/tests/qemuxml2argvdata/minimal-sandbox.args new file mode 100644 index 000000000..285cfed70 --- /dev/null +++ b/tests/qemuxml2argvdata/minimal-sandbox.args @@ -0,0 +1,25 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-i686 \ +-name QEMUGuest1 \ +-S \ +-M pc \ +-m 214 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-nographic \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-no-acpi \ +-boot c \ +-usb \ +-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \ +-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3 \ +-sandbox on,elevateprivileges=deny,spawn=deny diff --git a/tests/qemuxml2argvdata/minimal-sandbox.xml b/tests/qemuxml2argvdata/minimal-sandbox.xml new file mode 100644 index 000000000..9ef92f8fe --- /dev/null +++ b/tests/qemuxml2argvdata/minimal-sandbox.xml @@ -0,0 +1,34 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <title>A description of the test machine.</title> + <description> + A test of qemu's minimal configuration. + This test also tests the description and title elements. + </description> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' cpuset='1-4,8-20,525'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-i686</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 308d71f72..5fb16987f 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -691,6 +691,9 @@ mymain(void) unsetenv("SDL_AUDIODRIVER");
DO_TEST("minimal", NONE); + DO_TEST("minimal-sandbox", + QEMU_CAPS_SECCOMP_SANDBOX, + QEMU_CAPS_SECCOMP_BLACKLIST); DO_TEST_PARSE_ERROR("minimal-no-memory", NONE); DO_TEST("minimal-msg-timestamp", QEMU_CAPS_MSG_TIMESTAMP); DO_TEST("machine-aliases1", NONE); -- 2.13.6
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
participants (2)
-
Daniel P. Berrangé
-
Ján Tomko