[libvirt] [PATCH v2] qemu: Don't crash when parsing command line lacking -M

Andrea Bolognani abologna at redhat.com
Tue Oct 10 16:01:17 UTC 2017


Parse the -M (or -machine) command line option before starting
processing in earnest and have a fallback ready in case it's not
present, so that while parsing other options we can rely on
def->os.machine being initialized.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1379218

Signed-off-by: Andrea Bolognani <abologna at redhat.com>
---
Changes from [v1]:

  * rework command line parsing instead of adding checks to
    qemuDomainMachineIs*() functions

[v1] https://www.redhat.com/archives/libvir-list/2017-October/msg00406.html

 src/qemu/qemu_parse_command.c                      | 174 ++++++++++++---------
 .../qemuargv2xml-nomachine-aarch64.args            |  11 ++
 .../qemuargv2xml-nomachine-aarch64.xml             |  39 +++++
 .../qemuargv2xml-nomachine-ppc64.args              |  11 ++
 .../qemuargv2xml-nomachine-ppc64.xml               |  49 ++++++
 .../qemuargv2xml-nomachine-x86_64.args             |  11 ++
 .../qemuargv2xml-nomachine-x86_64.xml              |  48 ++++++
 tests/qemuargv2xmltest.c                           |   4 +
 8 files changed, 270 insertions(+), 77 deletions(-)
 create mode 100644 tests/qemuargv2xmldata/qemuargv2xml-nomachine-aarch64.args
 create mode 100644 tests/qemuargv2xmldata/qemuargv2xml-nomachine-aarch64.xml
 create mode 100644 tests/qemuargv2xmldata/qemuargv2xml-nomachine-ppc64.args
 create mode 100644 tests/qemuargv2xmldata/qemuargv2xml-nomachine-ppc64.xml
 create mode 100644 tests/qemuargv2xmldata/qemuargv2xml-nomachine-x86_64.args
 create mode 100644 tests/qemuargv2xmldata/qemuargv2xml-nomachine-x86_64.xml

diff --git a/src/qemu/qemu_parse_command.c b/src/qemu/qemu_parse_command.c
index 7c409b03a..aaa4d3703 100644
--- a/src/qemu/qemu_parse_command.c
+++ b/src/qemu/qemu_parse_command.c
@@ -1884,6 +1884,98 @@ qemuParseCommandLine(virCapsPtr caps,
         }
     }
 
+    /* Detect machine type before processing any other arguments,
+     * because they might depend on it */
+    for (i = 1; progargv[i]; i++) {
+        const char *arg = progargv[i];
+
+        /* Make sure we have a single - for all options to
+           simplify next logic */
+        if (STRPREFIX(arg, "--"))
+            arg++;
+
+        if (STREQ(arg, "-M") ||
+            STREQ(arg, "-machine")) {
+            char *param;
+            size_t j = 0;
+
+            /* -machine [type=]name[,prop[=value][,...]]
+             * Set os.machine only if first parameter lacks '=' or
+             * contains explicit type='...' */
+            WANT_VALUE();
+            if (!(list = virStringSplit(val, ",", 0)))
+                goto error;
+            param = list[0];
+
+            if (STRPREFIX(param, "type="))
+                param += strlen("type=");
+            if (!strchr(param, '=')) {
+                if (VIR_STRDUP(def->os.machine, param) < 0)
+                    goto error;
+                j++;
+            }
+
+            /* handle all remaining "-machine" parameters */
+            while ((param = list[j++])) {
+                if (STRPREFIX(param, "dump-guest-core=")) {
+                    param += strlen("dump-guest-core=");
+                    def->mem.dump_core = virTristateSwitchTypeFromString(param);
+                    if (def->mem.dump_core <= 0)
+                        def->mem.dump_core = VIR_TRISTATE_SWITCH_ABSENT;
+                } else if (STRPREFIX(param, "mem-merge=off")) {
+                    def->mem.nosharepages = true;
+                } else if (STRPREFIX(param, "accel=kvm")) {
+                    def->virtType = VIR_DOMAIN_VIRT_KVM;
+                    def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_TRISTATE_SWITCH_ON;
+                } else if (STRPREFIX(param, "aes-key-wrap=")) {
+                    if (STREQ(arg, "-M")) {
+                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                                       _("aes-key-wrap is not supported with "
+                                         "this QEMU binary"));
+                        goto error;
+                    }
+                    param += strlen("aes-key-wrap=");
+                    if (!def->keywrap && VIR_ALLOC(def->keywrap) < 0)
+                        goto error;
+                    def->keywrap->aes = virTristateSwitchTypeFromString(param);
+                    if (def->keywrap->aes < 0)
+                        def->keywrap->aes = VIR_TRISTATE_SWITCH_ABSENT;
+                } else if (STRPREFIX(param, "dea-key-wrap=")) {
+                    if (STREQ(arg, "-M")) {
+                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                                       _("dea-key-wrap is not supported with "
+                                         "this QEMU binary"));
+                        goto error;
+                    }
+                    param += strlen("dea-key-wrap=");
+                    if (!def->keywrap && VIR_ALLOC(def->keywrap) < 0)
+                        goto error;
+                    def->keywrap->dea = virTristateSwitchTypeFromString(param);
+                    if (def->keywrap->dea < 0)
+                        def->keywrap->dea = VIR_TRISTATE_SWITCH_ABSENT;
+                }
+            }
+            virStringListFree(list);
+            list = NULL;
+        }
+    }
+
+    /* If no machine type has been found among the arguments, then figure
+     * out a reasonable value by using capabilities */
+    if (!def->os.machine) {
+        virCapsDomainDataPtr capsdata;
+
+        if (!(capsdata = virCapabilitiesDomainDataLookup(caps, def->os.type,
+                def->os.arch, def->virtType, NULL, NULL)))
+            goto error;
+
+        if (VIR_STRDUP(def->os.machine, capsdata->machinetype) < 0) {
+            VIR_FREE(capsdata);
+            goto error;
+        }
+        VIR_FREE(capsdata);
+    }
+
     /* Now the real processing loop */
     for (i = 1; progargv[i]; i++) {
         const char *arg = progargv[i];
@@ -2137,69 +2229,6 @@ qemuParseCommandLine(virCapsPtr caps,
             }
             if (STREQ(def->name, ""))
                 VIR_FREE(def->name);
-        } else if (STREQ(arg, "-M") ||
-                   STREQ(arg, "-machine")) {
-            char *param;
-            size_t j = 0;
-
-            /* -machine [type=]name[,prop[=value][,...]]
-             * Set os.machine only if first parameter lacks '=' or
-             * contains explicit type='...' */
-            WANT_VALUE();
-            if (!(list = virStringSplit(val, ",", 0)))
-                goto error;
-            param = list[0];
-
-            if (STRPREFIX(param, "type="))
-                param += strlen("type=");
-            if (!strchr(param, '=')) {
-                if (VIR_STRDUP(def->os.machine, param) < 0)
-                    goto error;
-                j++;
-            }
-
-            /* handle all remaining "-machine" parameters */
-            while ((param = list[j++])) {
-                if (STRPREFIX(param, "dump-guest-core=")) {
-                    param += strlen("dump-guest-core=");
-                    def->mem.dump_core = virTristateSwitchTypeFromString(param);
-                    if (def->mem.dump_core <= 0)
-                        def->mem.dump_core = VIR_TRISTATE_SWITCH_ABSENT;
-                } else if (STRPREFIX(param, "mem-merge=off")) {
-                    def->mem.nosharepages = true;
-                } else if (STRPREFIX(param, "accel=kvm")) {
-                    def->virtType = VIR_DOMAIN_VIRT_KVM;
-                    def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_TRISTATE_SWITCH_ON;
-                } else if (STRPREFIX(param, "aes-key-wrap=")) {
-                    if (STREQ(arg, "-M")) {
-                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                                       _("aes-key-wrap is not supported with "
-                                         "this QEMU binary"));
-                        goto error;
-                    }
-                    param += strlen("aes-key-wrap=");
-                    if (!def->keywrap && VIR_ALLOC(def->keywrap) < 0)
-                        goto error;
-                    def->keywrap->aes = virTristateSwitchTypeFromString(param);
-                    if (def->keywrap->aes < 0)
-                        def->keywrap->aes = VIR_TRISTATE_SWITCH_ABSENT;
-                } else if (STRPREFIX(param, "dea-key-wrap=")) {
-                    if (STREQ(arg, "-M")) {
-                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                                       _("dea-key-wrap is not supported with "
-                                         "this QEMU binary"));
-                        goto error;
-                    }
-                    param += strlen("dea-key-wrap=");
-                    if (!def->keywrap && VIR_ALLOC(def->keywrap) < 0)
-                        goto error;
-                    def->keywrap->dea = virTristateSwitchTypeFromString(param);
-                    if (def->keywrap->dea < 0)
-                        def->keywrap->dea = VIR_TRISTATE_SWITCH_ABSENT;
-                }
-            }
-            virStringListFree(list);
-            list = NULL;
         } else if (STREQ(arg, "-serial")) {
             WANT_VALUE();
             if (STRNEQ(val, "none")) {
@@ -2489,6 +2518,11 @@ qemuParseCommandLine(virCapsPtr caps,
 
                 argRecognized = false;
             }
+        } else if (STREQ(arg, "-M") ||
+                   STREQ(arg, "-machine")) {
+            // This option has already been processed before entering this
+            // loop, so we just need to skip its argument and move along
+            WANT_VALUE();
         } else {
             argRecognized = false;
         }
@@ -2571,20 +2605,6 @@ qemuParseCommandLine(virCapsPtr caps,
         }
     }
 
-    if (!def->os.machine) {
-        virCapsDomainDataPtr capsdata;
-
-        if (!(capsdata = virCapabilitiesDomainDataLookup(caps, def->os.type,
-                def->os.arch, def->virtType, NULL, NULL)))
-            goto error;
-
-        if (VIR_STRDUP(def->os.machine, capsdata->machinetype) < 0) {
-            VIR_FREE(capsdata);
-            goto error;
-        }
-        VIR_FREE(capsdata);
-    }
-
     if (!nographics && (def->ngraphics == 0 || have_sdl)) {
         virDomainGraphicsDefPtr sdl;
         const char *display = qemuFindEnv(progenv, "DISPLAY");
diff --git a/tests/qemuargv2xmldata/qemuargv2xml-nomachine-aarch64.args b/tests/qemuargv2xmldata/qemuargv2xml-nomachine-aarch64.args
new file mode 100644
index 000000000..b17c0d0c2
--- /dev/null
+++ b/tests/qemuargv2xmldata/qemuargv2xml-nomachine-aarch64.args
@@ -0,0 +1,11 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu-system-aarch64 \
+-name QEMUGuest1 \
+-m 512 \
+-hda /dev/HostVG/QEMUGuest1 \
+-cdrom /root/boot.iso
diff --git a/tests/qemuargv2xmldata/qemuargv2xml-nomachine-aarch64.xml b/tests/qemuargv2xmldata/qemuargv2xml-nomachine-aarch64.xml
new file mode 100644
index 000000000..eb8f9db80
--- /dev/null
+++ b/tests/qemuargv2xmldata/qemuargv2xml-nomachine-aarch64.xml
@@ -0,0 +1,39 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>524288</memory>
+  <currentMemory unit='KiB'>524288</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='aarch64' machine='virt'>hvm</type>
+  </os>
+  <features>
+    <gic version='2'/>
+  </features>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu-system-aarch64</emulator>
+    <disk type='block' device='disk'>
+      <driver name='qemu' type='raw'/>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <disk type='file' device='cdrom'>
+      <driver name='qemu' type='raw'/>
+      <source file='/root/boot.iso'/>
+      <target dev='hdc' bus='ide'/>
+      <readonly/>
+      <address type='drive' controller='0' bus='1' target='0' unit='0'/>
+    </disk>
+    <controller type='ide' index='0'/>
+    <graphics type='sdl'/>
+    <video>
+      <model type='cirrus' vram='16384' heads='1' primary='yes'/>
+    </video>
+    <memballoon model='none'/>
+  </devices>
+</domain>
diff --git a/tests/qemuargv2xmldata/qemuargv2xml-nomachine-ppc64.args b/tests/qemuargv2xmldata/qemuargv2xml-nomachine-ppc64.args
new file mode 100644
index 000000000..ac618775e
--- /dev/null
+++ b/tests/qemuargv2xmldata/qemuargv2xml-nomachine-ppc64.args
@@ -0,0 +1,11 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu-system-ppc64 \
+-name QEMUGuest1 \
+-m 512 \
+-hda /dev/HostVG/QEMUGuest1 \
+-cdrom /root/boot.iso
diff --git a/tests/qemuargv2xmldata/qemuargv2xml-nomachine-ppc64.xml b/tests/qemuargv2xmldata/qemuargv2xml-nomachine-ppc64.xml
new file mode 100644
index 000000000..fa41070cb
--- /dev/null
+++ b/tests/qemuargv2xmldata/qemuargv2xml-nomachine-ppc64.xml
@@ -0,0 +1,49 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>524288</memory>
+  <currentMemory unit='KiB'>524288</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='ppc64' machine='pseries'>hvm</type>
+  </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-ppc64</emulator>
+    <disk type='block' device='disk'>
+      <driver name='qemu' type='raw'/>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda' bus='scsi'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <disk type='file' device='cdrom'>
+      <driver name='qemu' type='raw'/>
+      <source file='/root/boot.iso'/>
+      <target dev='hdc' bus='scsi'/>
+      <readonly/>
+      <address type='drive' controller='0' bus='0' target='0' unit='2'/>
+    </disk>
+    <controller type='usb' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'>
+      <model name='spapr-pci-host-bridge'/>
+      <target index='0'/>
+    </controller>
+    <controller type='scsi' index='0'>
+      <address type='spapr-vio' reg='0x2000'/>
+    </controller>
+    <input type='keyboard' bus='usb'/>
+    <input type='mouse' bus='usb'/>
+    <graphics type='sdl'/>
+    <video>
+      <model type='cirrus' vram='16384' heads='1' primary='yes'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+    </video>
+    <memballoon model='none'/>
+    <panic model='pseries'/>
+  </devices>
+</domain>
diff --git a/tests/qemuargv2xmldata/qemuargv2xml-nomachine-x86_64.args b/tests/qemuargv2xmldata/qemuargv2xml-nomachine-x86_64.args
new file mode 100644
index 000000000..22bc4fb1c
--- /dev/null
+++ b/tests/qemuargv2xmldata/qemuargv2xml-nomachine-x86_64.args
@@ -0,0 +1,11 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu-system-x86_64 \
+-name QEMUGuest1 \
+-m 512 \
+-hda /dev/HostVG/QEMUGuest1 \
+-cdrom /root/boot.iso
diff --git a/tests/qemuargv2xmldata/qemuargv2xml-nomachine-x86_64.xml b/tests/qemuargv2xmldata/qemuargv2xml-nomachine-x86_64.xml
new file mode 100644
index 000000000..71a36f083
--- /dev/null
+++ b/tests/qemuargv2xmldata/qemuargv2xml-nomachine-x86_64.xml
@@ -0,0 +1,48 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>524288</memory>
+  <currentMemory unit='KiB'>524288</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='x86_64' machine='pc-0.11'>hvm</type>
+  </os>
+  <features>
+    <acpi/>
+  </features>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu-system-x86_64</emulator>
+    <disk type='block' device='disk'>
+      <driver name='qemu' type='raw'/>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <disk type='file' device='cdrom'>
+      <driver name='qemu' type='raw'/>
+      <source file='/root/boot.iso'/>
+      <target dev='hdc' bus='ide'/>
+      <readonly/>
+      <address type='drive' controller='0' bus='1' target='0' unit='0'/>
+    </disk>
+    <controller type='usb' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'/>
+    <controller type='ide' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+    </controller>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <graphics type='sdl'/>
+    <video>
+      <model type='cirrus' vram='16384' heads='1' primary='yes'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+    </video>
+    <memballoon model='none'/>
+  </devices>
+</domain>
diff --git a/tests/qemuargv2xmltest.c b/tests/qemuargv2xmltest.c
index 1adbcfef6..5d261afa6 100644
--- a/tests/qemuargv2xmltest.c
+++ b/tests/qemuargv2xmltest.c
@@ -288,6 +288,10 @@ mymain(void)
     DO_TEST("machine-deakeywrap-off-argv");
     DO_TEST("machine-keywrap-none-argv");
 
+    DO_TEST("nomachine-x86_64");
+    DO_TEST("nomachine-aarch64");
+    DO_TEST("nomachine-ppc64");
+
     qemuTestDriverFree(&driver);
 
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
-- 
2.13.6




More information about the libvir-list mailing list