summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2022-07-14 18:14:12 +0100
committerPeter Maydell <peter.maydell@linaro.org>2022-07-14 18:14:12 +0100
commit285f64fcbf86dac2be6dbd0a8a32872bcff3cacb (patch)
tree1a30f398cbd4007b5ce8d955e24890eec84c90a6
parent8482ab545e52f50facacfe1118b22b97462724ab (diff)
parentc0b3607d5938f5ee7fd16ff1e102afe938fd4b39 (diff)
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging
* SCSI fuzzing fix (Mauro) * pre-install data files in the build directory (Akihiko) * SCSI fixes for Mac OS (Mark) # gpg: Signature made Wed 13 Jul 2022 15:59:00 BST # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full] # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * tag 'for-upstream' of https://gitlab.com/bonzini/qemu: pc-bios/s390-ccw: add -Wno-array-bounds q800: add default vendor and product information for scsi-cd devices q800: add default vendor and product information for scsi-hd devices scsi-disk: allow MODE SELECT block descriptor to set the block size scsi-disk: allow the MODE_PAGE_R_W_ERROR AWRE bit to be changeable for CDROM drives q800: implement compat_props to enable quirk_mode_page_truncated for scsi-cd devices scsi-disk: add SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED quirk for Macintosh scsi-disk: add FORMAT UNIT command q800: implement compat_props to enable quirk_mode_page_vendor_specific_apple for scsi devices scsi-disk: add SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE quirk for Macintosh q800: implement compat_props to enable quirk_mode_sense_rom_use_dbd for scsi-cd devices scsi-disk: add SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD quirk for Macintosh q800: implement compat_props to enable quirk_mode_page_apple_vendor for scsi-cd devices scsi-disk: add MODE_PAGE_APPLE_VENDOR quirk for Macintosh scsi-disk: add new quirks bitmap to SCSIDiskState meson: Prefix each element of firmware path module: Use bundle mechanism datadir: Use bundle mechanism cutils: Introduce bundle mechanism scsi/lsi53c895a: really fix use-after-free in lsi_do_msgout (CVE-2022-0216) Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--.travis.yml2
-rw-r--r--Makefile2
-rwxr-xr-xconfigure15
-rw-r--r--docs/about/build-platforms.rst2
-rw-r--r--hw/m68k/q800.c16
-rw-r--r--hw/scsi/lsi53c895a.c3
-rw-r--r--hw/scsi/scsi-disk.c96
-rw-r--r--hw/scsi/trace-events3
-rw-r--r--include/hw/scsi/scsi.h6
-rw-r--r--include/qemu/cutils.h18
-rw-r--r--include/scsi/constants.h2
-rw-r--r--meson.build15
-rw-r--r--meson_options.txt2
-rw-r--r--pc-bios/keymaps/meson.build21
-rw-r--r--pc-bios/meson.build13
-rw-r--r--pc-bios/s390-ccw/Makefile1
-rwxr-xr-xscripts/meson-buildoptions.py7
-rw-r--r--scripts/meson-buildoptions.sh4
-rwxr-xr-xscripts/oss-fuzz/build.sh8
-rw-r--r--scripts/symlink-install-tree.py33
-rw-r--r--softmmu/datadir.c30
-rw-r--r--tests/qtest/fuzz-lsi53c895a-test.c76
-rw-r--r--tests/qtest/fuzz/fuzz.c18
-rw-r--r--util/cutils.c68
-rw-r--r--util/meson.build1
-rw-r--r--util/module.c1
26 files changed, 349 insertions, 114 deletions
diff --git a/.travis.yml b/.travis.yml
index 9afc4a54b8..4fdc9a6785 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -223,7 +223,7 @@ jobs:
- BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$?
- |
if [ "$BUILD_RC" -eq 0 ] ; then
- mv pc-bios/s390-ccw/*.img pc-bios/ ;
+ mv pc-bios/s390-ccw/*.img qemu-bundle/usr/local/share/qemu ;
${TEST_CMD} ;
else
$(exit $BUILD_RC);
diff --git a/Makefile b/Makefile
index b4feda93c8..13234f2aa4 100644
--- a/Makefile
+++ b/Makefile
@@ -216,7 +216,7 @@ qemu-%.tar.bz2:
distclean: clean
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) -t clean -g || :
- rm -f config-host.mak
+ rm -f config-host.mak qemu-bundle
rm -f tests/tcg/config-*.mak
rm -f config.status
rm -f roms/seabios/config.mak
diff --git a/configure b/configure
index 465c5000ee..4f12481765 100755
--- a/configure
+++ b/configure
@@ -676,6 +676,21 @@ fi
werror=""
+meson_option_build_array() {
+ printf '['
+ (if test "$targetos" == windows; then
+ IFS=\;
+ else
+ IFS=:
+ fi
+ for e in $1; do
+ e=${e/'\'/'\\'}
+ e=${e/\"/'\"'}
+ printf '"""%s""",' "$e"
+ done)
+ printf ']\n'
+}
+
. $source_path/scripts/meson-buildoptions.sh
meson_options=
diff --git a/docs/about/build-platforms.rst b/docs/about/build-platforms.rst
index 1958edb430..ebde20f981 100644
--- a/docs/about/build-platforms.rst
+++ b/docs/about/build-platforms.rst
@@ -88,7 +88,7 @@ Windows
The project aims to support the two most recent versions of Windows that are
still supported by the vendor. The minimum Windows API that is currently
-targeted is "Windows 7", so theoretically the QEMU binaries can still be run
+targeted is "Windows 8", so theoretically the QEMU binaries can still be run
on older versions of Windows, too. However, such old versions of Windows are
not tested anymore, so it is recommended to use one of the latest versions of
Windows instead.
diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
index 099a758c6f..101ab0f803 100644
--- a/hw/m68k/q800.c
+++ b/hw/m68k/q800.c
@@ -686,6 +686,21 @@ static void q800_init(MachineState *machine)
}
}
+static GlobalProperty hw_compat_q800[] = {
+ { "scsi-hd", "quirk_mode_page_vendor_specific_apple", "on"},
+ { "scsi-hd", "vendor", " SEAGATE" },
+ { "scsi-hd", "product", " ST225N" },
+ { "scsi-hd", "ver", "1.0 " },
+ { "scsi-cd", "quirk_mode_page_apple_vendor", "on"},
+ { "scsi-cd", "quirk_mode_sense_rom_use_dbd", "on"},
+ { "scsi-cd", "quirk_mode_page_vendor_specific_apple", "on"},
+ { "scsi-cd", "quirk_mode_page_truncated", "on"},
+ { "scsi-cd", "vendor", "MATSHITA" },
+ { "scsi-cd", "product", "CD-ROM CR-8005" },
+ { "scsi-cd", "ver", "1.0k" },
+};
+static const size_t hw_compat_q800_len = G_N_ELEMENTS(hw_compat_q800);
+
static void q800_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -695,6 +710,7 @@ static void q800_machine_class_init(ObjectClass *oc, void *data)
mc->max_cpus = 1;
mc->block_default_type = IF_SCSI;
mc->default_ram_id = "m68k_mac.ram";
+ compat_props_add(mc->compat_props, hw_compat_q800, hw_compat_q800_len);
}
static const TypeInfo q800_machine_typeinfo = {
diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
index 99ea42d49b..ad5f5e5f39 100644
--- a/hw/scsi/lsi53c895a.c
+++ b/hw/scsi/lsi53c895a.c
@@ -1030,7 +1030,7 @@ static void lsi_do_msgout(LSIState *s)
trace_lsi_do_msgout_abort(current_tag);
if (current_req && current_req->req) {
scsi_req_cancel(current_req->req);
- current_req->req = NULL;
+ current_req = NULL;
}
lsi_disconnect(s);
break;
@@ -1056,6 +1056,7 @@ static void lsi_do_msgout(LSIState *s)
/* clear the current I/O process */
if (s->current) {
scsi_req_cancel(s->current->req);
+ current_req = NULL;
}
/* As the current implemented devices scsi_disk and scsi_generic
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 91acb5c0ce..f5cdb9ad4b 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -94,6 +94,7 @@ struct SCSIDiskState {
uint16_t port_index;
uint64_t max_unmap_size;
uint64_t max_io_size;
+ uint32_t quirks;
QEMUBH *bh;
char *version;
char *serial;
@@ -1078,12 +1079,14 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
int page_control)
{
static const int mode_sense_valid[0x3f] = {
+ [MODE_PAGE_VENDOR_SPECIFIC] = (1 << TYPE_DISK) | (1 << TYPE_ROM),
[MODE_PAGE_HD_GEOMETRY] = (1 << TYPE_DISK),
[MODE_PAGE_FLEXIBLE_DISK_GEOMETRY] = (1 << TYPE_DISK),
[MODE_PAGE_CACHING] = (1 << TYPE_DISK) | (1 << TYPE_ROM),
[MODE_PAGE_R_W_ERROR] = (1 << TYPE_DISK) | (1 << TYPE_ROM),
[MODE_PAGE_AUDIO_CTL] = (1 << TYPE_ROM),
[MODE_PAGE_CAPABILITIES] = (1 << TYPE_ROM),
+ [MODE_PAGE_APPLE_VENDOR] = (1 << TYPE_ROM),
};
uint8_t *p = *p_outbuf + 2;
@@ -1185,6 +1188,10 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
case MODE_PAGE_R_W_ERROR:
length = 10;
if (page_control == 1) { /* Changeable Values */
+ if (s->qdev.type == TYPE_ROM) {
+ /* Automatic Write Reallocation Enabled */
+ p[0] = 0x80;
+ }
break;
}
p[0] = 0x80; /* Automatic Write Reallocation Enabled */
@@ -1228,6 +1235,36 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
p[19] = (16 * 176) & 0xff;
break;
+ case MODE_PAGE_APPLE_VENDOR:
+ if (s->quirks & (1 << SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR)) {
+ length = 0x1e;
+ if (page_control == 1) { /* Changeable Values */
+ break;
+ }
+
+ memset(p, 0, length);
+ strcpy((char *)p + 8, "APPLE COMPUTER, INC ");
+ break;
+ } else {
+ return -1;
+ }
+
+ case MODE_PAGE_VENDOR_SPECIFIC:
+ if (s->qdev.type == TYPE_DISK && (s->quirks &
+ (1 << SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE))) {
+ length = 0x2;
+ if (page_control == 1) { /* Changeable Values */
+ p[0] = 0xff;
+ p[1] = 0xff;
+ break;
+ }
+ p[0] = 0;
+ p[1] = 0;
+ break;
+ } else {
+ return -1;
+ }
+
default:
return -1;
}
@@ -1263,10 +1300,27 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
dev_specific_param |= 0x80; /* Readonly. */
}
} else {
- /* MMC prescribes that CD/DVD drives have no block descriptors,
- * and defines no device-specific parameter. */
- dev_specific_param = 0x00;
- dbd = true;
+ if (s->quirks & (1 << SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD)) {
+ /* Use DBD from the request... */
+ dev_specific_param = 0x00;
+
+ /*
+ * ... unless we receive a request for MODE_PAGE_APPLE_VENDOR
+ * which should never return a block descriptor even though DBD is
+ * not set, otherwise CDROM detection fails in MacOS
+ */
+ if (s->quirks & (1 << SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR) &&
+ page == MODE_PAGE_APPLE_VENDOR) {
+ dbd = true;
+ }
+ } else {
+ /*
+ * MMC prescribes that CD/DVD drives have no block descriptors,
+ * and defines no device-specific parameter.
+ */
+ dev_specific_param = 0x00;
+ dbd = true;
+ }
}
if (r->req.cmd.buf[0] == MODE_SENSE) {
@@ -1502,7 +1556,10 @@ static int mode_select_pages(SCSIDiskReq *r, uint8_t *p, int len, bool change)
goto invalid_param;
}
if (page_len > len) {
- goto invalid_param_len;
+ if (!(s->quirks & SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED)) {
+ goto invalid_param_len;
+ }
+ trace_scsi_disk_mode_select_page_truncated(page, page_len, len);
}
if (!change) {
@@ -1537,9 +1594,12 @@ static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf)
int bd_len;
int pass;
- /* We only support PF=1, SP=0. */
if ((r->req.cmd.buf[1] & 0x11) != 0x10) {
- goto invalid_field;
+ if (!(s->quirks &
+ (1 << SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE))) {
+ /* We only support PF=1, SP=0. */
+ goto invalid_field;
+ }
}
if (len < hdr_len) {
@@ -1556,6 +1616,12 @@ static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf)
goto invalid_param;
}
+ /* Allow changing the block size */
+ if (bd_len && p[6] != (s->qdev.blocksize >> 8)) {
+ s->qdev.blocksize = p[6] << 8;
+ trace_scsi_disk_mode_select_set_blocksize(s->qdev.blocksize);
+ }
+
len -= bd_len;
p += bd_len;
@@ -2127,6 +2193,9 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
trace_scsi_disk_emulate_command_WRITE_SAME(
req->cmd.buf[0] == WRITE_SAME_10 ? 10 : 16, r->req.cmd.xfer);
break;
+ case FORMAT_UNIT:
+ trace_scsi_disk_emulate_command_FORMAT_UNIT(r->req.cmd.xfer);
+ break;
default:
trace_scsi_disk_emulate_command_UNKNOWN(buf[0],
scsi_command_name(buf[0]));
@@ -2532,6 +2601,7 @@ static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
[VERIFY_10] = &scsi_disk_emulate_reqops,
[VERIFY_12] = &scsi_disk_emulate_reqops,
[VERIFY_16] = &scsi_disk_emulate_reqops,
+ [FORMAT_UNIT] = &scsi_disk_emulate_reqops,
[READ_6] = &scsi_disk_dma_reqops,
[READ_10] = &scsi_disk_dma_reqops,
@@ -3036,6 +3106,9 @@ static Property scsi_hd_properties[] = {
DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0),
DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version,
5),
+ DEFINE_PROP_BIT("quirk_mode_page_vendor_specific_apple", SCSIDiskState,
+ quirks, SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE,
+ 0),
DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf),
DEFINE_PROP_END_OF_LIST(),
};
@@ -3084,6 +3157,15 @@ static Property scsi_cd_properties[] = {
DEFAULT_MAX_IO_SIZE),
DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version,
5),
+ DEFINE_PROP_BIT("quirk_mode_page_apple_vendor", SCSIDiskState, quirks,
+ SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR, 0),
+ DEFINE_PROP_BIT("quirk_mode_sense_rom_use_dbd", SCSIDiskState, quirks,
+ SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD, 0),
+ DEFINE_PROP_BIT("quirk_mode_page_vendor_specific_apple", SCSIDiskState,
+ quirks, SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE,
+ 0),
+ DEFINE_PROP_BIT("quirk_mode_page_truncated", SCSIDiskState, quirks,
+ SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED, 0),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events
index 20fb0dc162..ab238293f0 100644
--- a/hw/scsi/trace-events
+++ b/hw/scsi/trace-events
@@ -334,10 +334,13 @@ scsi_disk_emulate_command_UNMAP(size_t xfer) "Unmap (len %zd)"
scsi_disk_emulate_command_VERIFY(int bytchk) "Verify (bytchk %d)"
scsi_disk_emulate_command_WRITE_SAME(int cmd, size_t xfer) "WRITE SAME %d (len %zd)"
scsi_disk_emulate_command_UNKNOWN(int cmd, const char *name) "Unknown SCSI command (0x%2.2x=%s)"
+scsi_disk_emulate_command_FORMAT_UNIT(size_t xfer) "Format Unit (len %zu)"
scsi_disk_dma_command_READ(uint64_t lba, uint32_t len) "Read (sector %" PRId64 ", count %u)"
scsi_disk_dma_command_WRITE(const char *cmd, uint64_t lba, int len) "Write %s(sector %" PRId64 ", count %u)"
scsi_disk_new_request(uint32_t lun, uint32_t tag, const char *line) "Command: lun=%d tag=0x%x data=%s"
scsi_disk_aio_sgio_command(uint32_t tag, uint8_t cmd, uint64_t lba, int len, uint32_t timeout) "disk aio sgio: tag=0x%x cmd=0x%x (sector %" PRId64 ", count %d) timeout=%u"
+scsi_disk_mode_select_page_truncated(int page, int len, int page_len) "page %d expected length %d but received length %d"
+scsi_disk_mode_select_set_blocksize(int blocksize) "set block size to %d"
# scsi-generic.c
scsi_generic_command_complete_noio(void *req, uint32_t tag, int statuc) "Command complete %p tag=0x%x status=%d"
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
index 1ffb367f94..e284e3a4ec 100644
--- a/include/hw/scsi/scsi.h
+++ b/include/hw/scsi/scsi.h
@@ -226,4 +226,10 @@ SCSIDevice *scsi_device_get(SCSIBus *bus, int channel, int target, int lun);
/* scsi-generic.c. */
extern const SCSIReqOps scsi_generic_req_ops;
+/* scsi-disk.c */
+#define SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR 0
+#define SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD 1
+#define SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE 2
+#define SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED 3
+
#endif
diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h
index d3e532b64c..92c436d8c7 100644
--- a/include/qemu/cutils.h
+++ b/include/qemu/cutils.h
@@ -224,9 +224,21 @@ const char *qemu_get_exec_dir(void);
* @dir: the directory (typically a `CONFIG_*DIR` variable) to be relocated.
*
* Returns a path for @dir that uses the directory of the running executable
- * as the prefix. For example, if `bindir` is `/usr/bin` and @dir is
- * `/usr/share/qemu`, the function will append `../share/qemu` to the
- * directory that contains the running executable and return the result.
+ * as the prefix.
+ *
+ * When a directory named `qemu-bundle` exists in the directory of the running
+ * executable, the path to the directory will be prepended to @dir. For
+ * example, if the directory of the running executable is `/qemu/build` @dir
+ * is `/usr/share/qemu`, the result will be
+ * `/qemu/build/qemu-bundle/usr/share/qemu`. The directory is expected to exist
+ * in the build tree.
+ *
+ * Otherwise, the directory of the running executable will be used as the
+ * prefix and it appends the relative path from `bindir` to @dir. For example,
+ * if the directory of the running executable is `/opt/qemu/bin`, `bindir` is
+ * `/usr/bin` and @dir is `/usr/share/qemu`, the result will be
+ * `/opt/qemu/bin/../share/qemu`.
+ *
* The returned string should be freed by the caller.
*/
char *get_relocated_path(const char *dir);
diff --git a/include/scsi/constants.h b/include/scsi/constants.h
index 2a32c08b5e..6a8bad556a 100644
--- a/include/scsi/constants.h
+++ b/include/scsi/constants.h
@@ -225,6 +225,7 @@
#define TYPE_NO_LUN 0x7f
/* Mode page codes for mode sense/set */
+#define MODE_PAGE_VENDOR_SPECIFIC 0x00
#define MODE_PAGE_R_W_ERROR 0x01
#define MODE_PAGE_HD_GEOMETRY 0x04
#define MODE_PAGE_FLEXIBLE_DISK_GEOMETRY 0x05
@@ -234,6 +235,7 @@
#define MODE_PAGE_FAULT_FAIL 0x1c
#define MODE_PAGE_TO_PROTECT 0x1d
#define MODE_PAGE_CAPABILITIES 0x2a
+#define MODE_PAGE_APPLE_VENDOR 0x30
#define MODE_PAGE_ALLS 0x3f
/* Not in Mt. Fuji, but in ATAPI 2.6 -- deprecated now in favor
* of MODE_PAGE_SENSE_POWER */
diff --git a/meson.build b/meson.build
index fea3566ea8..8a8c415fc1 100644
--- a/meson.build
+++ b/meson.build
@@ -7,6 +7,8 @@ add_test_setup('quick', exclude_suites: ['slow', 'thorough'], is_default: true)
add_test_setup('slow', exclude_suites: ['thorough'], env: ['G_TEST_SLOW=1', 'SPEED=slow'])
add_test_setup('thorough', env: ['G_TEST_SLOW=1', 'SPEED=thorough'])
+meson.add_postconf_script(find_program('scripts/symlink-install-tree.py'))
+
not_found = dependency('', required: false)
keyval = import('keyval')
ss = import('sourceset')
@@ -356,10 +358,12 @@ nvmm =not_found
hvf = not_found
midl = not_found
widl = not_found
+pathcch = not_found
host_dsosuf = '.so'
if targetos == 'windows'
midl = find_program('midl', required: false)
widl = find_program('widl', required: false)
+ pathcch = cc.find_library('pathcch')
socket = cc.find_library('ws2_32')
winmm = cc.find_library('winmm')
@@ -1715,7 +1719,13 @@ config_host_data.set_quoted('CONFIG_PREFIX', get_option('prefix'))
config_host_data.set_quoted('CONFIG_QEMU_CONFDIR', get_option('prefix') / qemu_confdir)
config_host_data.set_quoted('CONFIG_QEMU_DATADIR', get_option('prefix') / qemu_datadir)
config_host_data.set_quoted('CONFIG_QEMU_DESKTOPDIR', get_option('prefix') / qemu_desktopdir)
-config_host_data.set_quoted('CONFIG_QEMU_FIRMWAREPATH', get_option('prefix') / get_option('qemu_firmwarepath'))
+
+qemu_firmwarepath = ''
+foreach k : get_option('qemu_firmwarepath')
+ qemu_firmwarepath += '"' + get_option('prefix') / k + '", '
+endforeach
+config_host_data.set('CONFIG_QEMU_FIRMWAREPATH', qemu_firmwarepath)
+
config_host_data.set_quoted('CONFIG_QEMU_HELPERDIR', get_option('prefix') / get_option('libexecdir'))
config_host_data.set_quoted('CONFIG_QEMU_ICONDIR', get_option('prefix') / qemu_icondir)
config_host_data.set_quoted('CONFIG_QEMU_LOCALEDIR', get_option('prefix') / get_option('localedir'))
@@ -3680,7 +3690,8 @@ endif
summary_info = {}
summary_info += {'Install prefix': get_option('prefix')}
summary_info += {'BIOS directory': qemu_datadir}
-summary_info += {'firmware path': get_option('prefix') / get_option('qemu_firmwarepath')}
+pathsep = targetos == 'windows' ? ';' : ':'
+summary_info += {'firmware path': pathsep.join(get_option('qemu_firmwarepath'))}
summary_info += {'binary directory': get_option('prefix') / get_option('bindir')}
summary_info += {'library directory': get_option('prefix') / get_option('libdir')}
summary_info += {'module directory': qemu_moddir}
diff --git a/meson_options.txt b/meson_options.txt
index 9a034f875b..e58e158396 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -6,7 +6,7 @@ option('qemu_suffix', type : 'string', value: 'qemu',
description: 'Suffix for QEMU data/modules/config directories (can be empty)')
option('docdir', type : 'string', value : 'share/doc',
description: 'Base directory for documentation installation (can be empty)')
-option('qemu_firmwarepath', type : 'string', value : 'share/qemu-firmware',
+option('qemu_firmwarepath', type : 'array', value : ['share/qemu-firmware'],
description: 'search PATH for firmware files')
option('pkgversion', type : 'string', value : '',
description: 'use specified string as sub-version of the package')
diff --git a/pc-bios/keymaps/meson.build b/pc-bios/keymaps/meson.build
index 44247a12b5..2837eb34f4 100644
--- a/pc-bios/keymaps/meson.build
+++ b/pc-bios/keymaps/meson.build
@@ -40,9 +40,9 @@ else
endif
cp = find_program('cp')
-t = []
-foreach km, args: keymaps
- if native_qemu_keymap.found()
+if native_qemu_keymap.found()
+ t = []
+ foreach km, args: keymaps
# generate with qemu-kvm
t += custom_target(km,
build_by_default: true,
@@ -50,20 +50,11 @@ foreach km, args: keymaps
command: [native_qemu_keymap, '-f', '@OUTPUT@', args.split()],
install: true,
install_dir: qemu_datadir / 'keymaps')
- else
- # copy from source tree
- t += custom_target(km,
- build_by_default: true,
- input: km,
- output: km,
- command: [cp, '@INPUT@', '@OUTPUT@'],
- install: true,
- install_dir: qemu_datadir / 'keymaps')
- endif
-endforeach
+ endforeach
-if native_qemu_keymap.found()
alias_target('update-keymaps', t)
+else
+ install_data(keymaps.keys(), install_dir: qemu_datadir / 'keymaps')
endif
install_data(['sl', 'sv'], install_dir: qemu_datadir / 'keymaps')
diff --git a/pc-bios/meson.build b/pc-bios/meson.build
index 41ba1c0ec7..388e0db6e4 100644
--- a/pc-bios/meson.build
+++ b/pc-bios/meson.build
@@ -85,16 +85,9 @@ blobs = [
'vof-nvram.bin',
]
-ln_s = [find_program('ln', required: true), '-sf']
-foreach f : blobs
- roms += custom_target(f,
- build_by_default: have_system,
- output: f,
- input: files('meson.build'), # dummy input
- install: get_option('install_blobs'),
- install_dir: qemu_datadir,
- command: [ ln_s, meson.project_source_root() / 'pc-bios' / f, '@OUTPUT@' ])
-endforeach
+if get_option('install_blobs')
+ install_data(blobs, install_dir: qemu_datadir)
+endif
subdir('descriptors')
subdir('keymaps')
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 26ad40f94e..c8784c2a08 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -35,6 +35,7 @@ EXTRA_CFLAGS += $(call cc-option,-Werror $(EXTRA_CFLAGS),-Wno-stringop-overflow)
EXTRA_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -fno-common -fPIE
EXTRA_CFLAGS += -fwrapv -fno-strict-aliasing -fno-asynchronous-unwind-tables
EXTRA_CFLAGS += $(call cc-option, $(EXTRA_CFLAGS), -fno-stack-protector)
+EXTRA_CFLAGS += $(call cc-option, $(EXTRA_CFLAGS), -Wno-array-bounds)
EXTRA_CFLAGS += -msoft-float
EXTRA_CFLAGS += $(call cc-option, $(EXTRA_CFLAGS),-march=z900,-march=z10)
EXTRA_CFLAGS += -std=gnu99
diff --git a/scripts/meson-buildoptions.py b/scripts/meson-buildoptions.py
index e624c16b01..3e2b478538 100755
--- a/scripts/meson-buildoptions.py
+++ b/scripts/meson-buildoptions.py
@@ -156,7 +156,7 @@ def cli_metavar(opt):
if opt["type"] == "string":
return "VALUE"
if opt["type"] == "array":
- return "CHOICES"
+ return "CHOICES" if "choices" in opt else "VALUES"
return "CHOICE"
@@ -199,7 +199,10 @@ def print_parse(options):
key = cli_option(opt)
name = opt["name"]
if require_arg(opt):
- print(f' --{key}=*) quote_sh "-D{name}=$2" ;;')
+ if opt["type"] == "array" and not "choices" in opt:
+ print(f' --{key}=*) quote_sh "-D{name}=$(meson_option_build_array $2)" ;;')
+ else:
+ print(f' --{key}=*) quote_sh "-D{name}=$2" ;;')
elif opt["type"] == "boolean":
print(f' --enable-{key}) printf "%s" -D{name}=true ;;')
print(f' --disable-{key}) printf "%s" -D{name}=false ;;')
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 4b7b8ffaa2..359b04e0e6 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -42,7 +42,7 @@ meson_options_help() {
printf "%s\n" ' --enable-trace-backends=CHOICES'
printf "%s\n" ' Set available tracing backends [log] (choices:'
printf "%s\n" ' dtrace/ftrace/log/nop/simple/syslog/ust)'
- printf "%s\n" ' --firmwarepath=VALUE search PATH for firmware files [share/qemu-firmware]'
+ printf "%s\n" ' --firmwarepath=VALUES search PATH for firmware files [share/qemu-firmware]'
printf "%s\n" ' --iasl=VALUE Path to ACPI disassembler'
printf "%s\n" ' --includedir=VALUE Header file directory [include]'
printf "%s\n" ' --interp-prefix=VALUE where to find shared libraries etc., use %M for'
@@ -363,7 +363,7 @@ _meson_option_parse() {
--disable-qcow1) printf "%s" -Dqcow1=disabled ;;
--enable-qed) printf "%s" -Dqed=enabled ;;
--disable-qed) printf "%s" -Dqed=disabled ;;
- --firmwarepath=*) quote_sh "-Dqemu_firmwarepath=$2" ;;
+ --firmwarepath=*) quote_sh "-Dqemu_firmwarepath=$(meson_option_build_array $2)" ;;
--enable-qga-vss) printf "%s" -Dqga_vss=enabled ;;
--disable-qga-vss) printf "%s" -Dqga_vss=disabled ;;
--enable-qom-cast-debug) printf "%s" -Dqom_cast_debug=true ;;
diff --git a/scripts/oss-fuzz/build.sh b/scripts/oss-fuzz/build.sh
index aaf485cb55..2656a89aea 100755
--- a/scripts/oss-fuzz/build.sh
+++ b/scripts/oss-fuzz/build.sh
@@ -64,7 +64,7 @@ mkdir -p "$DEST_DIR/lib/" # Copy the shared libraries here
# Build once to get the list of dynamic lib paths, and copy them over
../configure --disable-werror --cc="$CC" --cxx="$CXX" --enable-fuzzing \
- --prefix="$DEST_DIR" --bindir="$DEST_DIR" --datadir="$DEST_DIR/data/" \
+ --prefix="/opt/qemu-oss-fuzz" \
--extra-cflags="$EXTRA_CFLAGS" --target-list="i386-softmmu"
if ! make "-j$(nproc)" qemu-fuzz-i386; then
@@ -81,14 +81,14 @@ if [ "$GITLAB_CI" != "true" ]; then
# Build a second time to build the final binary with correct rpath
../configure --disable-werror --cc="$CC" --cxx="$CXX" --enable-fuzzing \
- --prefix="$DEST_DIR" --bindir="$DEST_DIR" --datadir="$DEST_DIR/data/" \
+ --prefix="/opt/qemu-oss-fuzz" \
--extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="-Wl,-rpath,\$ORIGIN/lib" \
--target-list="i386-softmmu"
make "-j$(nproc)" qemu-fuzz-i386 V=1
fi
-# Copy over the datadir
-cp -r ../pc-bios/ "$DEST_DIR/pc-bios"
+# Prepare a preinstalled tree
+make install DESTDIR=$DEST_DIR/qemu-bundle
targets=$(./qemu-fuzz-i386 | awk '$1 ~ /\*/ {print $2}')
base_copy="$DEST_DIR/qemu-fuzz-i386-target-$(echo "$targets" | head -n 1)"
diff --git a/scripts/symlink-install-tree.py b/scripts/symlink-install-tree.py
new file mode 100644
index 0000000000..a5bf0b0d6d
--- /dev/null
+++ b/scripts/symlink-install-tree.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python3
+
+from pathlib import PurePath
+import errno
+import json
+import os
+import subprocess
+import sys
+
+def destdir_join(d1: str, d2: str) -> str:
+ if not d1:
+ return d2
+ # c:\destdir + c:\prefix must produce c:\destdir\prefix
+ return str(PurePath(d1, *PurePath(d2).parts[1:]))
+
+introspect = os.environ.get('MESONINTROSPECT')
+out = subprocess.run([*introspect.split(' '), '--installed'],
+ stdout=subprocess.PIPE, check=True).stdout
+for source, dest in json.loads(out).items():
+ assert os.path.isabs(source)
+ bundle_dest = destdir_join('qemu-bundle', dest)
+ path = os.path.dirname(bundle_dest)
+ try:
+ os.makedirs(path, exist_ok=True)
+ except BaseException as e:
+ print(f'error making directory {path}', file=sys.stderr)
+ raise e
+ try:
+ os.symlink(source, bundle_dest)
+ except BaseException as e:
+ if not isinstance(e, OSError) or e.errno != errno.EEXIST:
+ print(f'error making symbolic link {dest}', file=sys.stderr)
+ raise e
diff --git a/softmmu/datadir.c b/softmmu/datadir.c
index 160cac999a..c9237cb5d4 100644
--- a/softmmu/datadir.c
+++ b/softmmu/datadir.c
@@ -83,40 +83,22 @@ void qemu_add_data_dir(char *path)
data_dir[data_dir_idx++] = path;
}
-/*
- * Find a likely location for support files using the location of the binary.
- * When running from the build tree this will be "$bindir/pc-bios".
- * Otherwise, this is CONFIG_QEMU_DATADIR (possibly relocated).
- *
- * The caller must use g_free() to free the returned data when it is
- * no longer required.
- */
-static char *find_datadir(void)
-{
- g_autofree char *dir = NULL;
-
- dir = g_build_filename(qemu_get_exec_dir(), "pc-bios", NULL);
- if (g_file_test(dir, G_FILE_TEST_IS_DIR)) {
- return g_steal_pointer(&dir);
- }
-
- return get_relocated_path(CONFIG_QEMU_DATADIR);
-}
-
void qemu_add_default_firmwarepath(void)
{
- char **dirs;
+ static const char * const dirs[] = {
+ CONFIG_QEMU_FIRMWAREPATH
+ NULL
+ };
+
size_t i;
/* add configured firmware directories */
- dirs = g_strsplit(CONFIG_QEMU_FIRMWAREPATH, G_SEARCHPATH_SEPARATOR_S, 0);
for (i = 0; dirs[i] != NULL; i++) {
qemu_add_data_dir(get_relocated_path(dirs[i]));
}
- g_strfreev(dirs);
/* try to find datadir relative to the executable path */
- qemu_add_data_dir(find_datadir());
+ qemu_add_data_dir(get_relocated_path(CONFIG_QEMU_DATADIR));
}
void qemu_list_data_dirs(void)
diff --git a/tests/qtest/fuzz-lsi53c895a-test.c b/tests/qtest/fuzz-lsi53c895a-test.c
index 2e8e67859e..b23d3ecf45 100644
--- a/tests/qtest/fuzz-lsi53c895a-test.c
+++ b/tests/qtest/fuzz-lsi53c895a-test.c
@@ -9,6 +9,79 @@
#include "libqtest.h"
/*
+ * This used to trigger a UAF in lsi_do_msgout()
+ * https://gitlab.com/qemu-project/qemu/-/issues/972
+ */
+static void test_lsi_do_msgout_cancel_req(void)
+{
+ QTestState *s;
+
+ if (sizeof(void *) == 4) {
+ g_test_skip("memory size too big for 32-bit build");
+ return;
+ }
+
+ s = qtest_init("-M q35 -m 4G -display none -nodefaults "
+ "-device lsi53c895a,id=scsi "
+ "-device scsi-hd,drive=disk0 "
+ "-drive file=null-co://,id=disk0,if=none,format=raw");
+
+ qtest_outl(s, 0xcf8, 0x80000810);
+ qtest_outl(s, 0xcf8, 0xc000);
+ qtest_outl(s, 0xcf8, 0x80000810);
+ qtest_outw(s, 0xcfc, 0x7);
+ qtest_outl(s, 0xcf8, 0x80000810);
+ qtest_outl(s, 0xcfc, 0xc000);
+ qtest_outl(s, 0xcf8, 0x80000804);
+ qtest_outw(s, 0xcfc, 0x05);
+ qtest_writeb(s, 0x69736c10, 0x08);
+ qtest_writeb(s, 0x69736c13, 0x58);
+ qtest_writeb(s, 0x69736c1a, 0x01);
+ qtest_writeb(s, 0x69736c1b, 0x06);
+ qtest_writeb(s, 0x69736c22, 0x01);
+ qtest_writeb(s, 0x69736c23, 0x07);
+ qtest_writeb(s, 0x69736c2b, 0x02);
+ qtest_writeb(s, 0x69736c48, 0x08);
+ qtest_writeb(s, 0x69736c4b, 0x58);
+ qtest_writeb(s, 0x69736c52, 0x04);
+ qtest_writeb(s, 0x69736c53, 0x06);
+ qtest_writeb(s, 0x69736c5b, 0x02);
+ qtest_outl(s, 0xc02d, 0x697300);
+ qtest_writeb(s, 0x5a554662, 0x01);
+ qtest_writeb(s, 0x5a554663, 0x07);
+ qtest_writeb(s, 0x5a55466a, 0x10);
+ qtest_writeb(s, 0x5a55466b, 0x22);
+ qtest_writeb(s, 0x5a55466c, 0x5a);
+ qtest_writeb(s, 0x5a55466d, 0x5a);
+ qtest_writeb(s, 0x5a55466e, 0x34);
+ qtest_writeb(s, 0x5a55466f, 0x5a);
+ qtest_writeb(s, 0x5a345a5a, 0x77);
+ qtest_writeb(s, 0x5a345a5b, 0x55);
+ qtest_writeb(s, 0x5a345a5c, 0x51);
+ qtest_writeb(s, 0x5a345a5d, 0x27);
+ qtest_writeb(s, 0x27515577, 0x41);
+ qtest_outl(s, 0xc02d, 0x5a5500);
+ qtest_writeb(s, 0x364001d0, 0x08);
+ qtest_writeb(s, 0x364001d3, 0x58);
+ qtest_writeb(s, 0x364001da, 0x01);
+ qtest_writeb(s, 0x364001db, 0x26);
+ qtest_writeb(s, 0x364001dc, 0x0d);
+ qtest_writeb(s, 0x364001dd, 0xae);
+ qtest_writeb(s, 0x364001de, 0x41);
+ qtest_writeb(s, 0x364001df, 0x5a);
+ qtest_writeb(s, 0x5a41ae0d, 0xf8);
+ qtest_writeb(s, 0x5a41ae0e, 0x36);
+ qtest_writeb(s, 0x5a41ae0f, 0xd7);
+ qtest_writeb(s, 0x5a41ae10, 0x36);
+ qtest_writeb(s, 0x36d736f8, 0x0c);
+ qtest_writeb(s, 0x36d736f9, 0x80);
+ qtest_writeb(s, 0x36d736fa, 0x0d);
+ qtest_outl(s, 0xc02d, 0x364000);
+
+ qtest_quit(s);
+}
+
+/*
* This used to trigger the assert in lsi_do_dma()
* https://bugs.launchpad.net/qemu/+bug/697510
* https://bugs.launchpad.net/qemu/+bug/1905521
@@ -44,5 +117,8 @@ int main(int argc, char **argv)
qtest_add_func("fuzz/lsi53c895a/lsi_do_dma_empty_queue",
test_lsi_do_dma_empty_queue);
+ qtest_add_func("fuzz/lsi53c895a/lsi_do_msgout_cancel_req",
+ test_lsi_do_msgout_cancel_req);
+
return g_test_run();
}
diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c
index 0ad4ba9e94..2b3bc1fb9d 100644
--- a/tests/qtest/fuzz/fuzz.c
+++ b/tests/qtest/fuzz/fuzz.c
@@ -158,8 +158,6 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp)
{
char *target_name;
- const char *bindir;
- char *datadir;
GString *cmd_line;
gchar *pretty_cmd_line;
bool serialize = false;
@@ -174,22 +172,6 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp)
target_name = strstr(**argv, "-target-");
if (target_name) { /* The binary name specifies the target */
target_name += strlen("-target-");
- /*
- * With oss-fuzz, the executable is kept in the root of a directory (we
- * cannot assume the path). All data (including bios binaries) must be
- * in the same dir, or a subdir. Thus, we cannot place the pc-bios so
- * that it would be in exec_dir/../pc-bios.
- * As a workaround, oss-fuzz allows us to use argv[0] to get the
- * location of the executable. Using this we add exec_dir/pc-bios to
- * the datadirs.
- */
- bindir = qemu_get_exec_dir();
- datadir = g_build_filename(bindir, "pc-bios", NULL);
- if (g_file_test(datadir, G_FILE_TEST_IS_DIR)) {
- qemu_add_data_dir(datadir);
- } else {
- g_free(datadir);
- }
} else if (*argc > 1) { /* The target is specified as an argument */
target_name = (*argv)[1];
if (!strstr(target_name, "--fuzz-target=")) {
diff --git a/util/cutils.c b/util/cutils.c
index 6d04e52907..8199dac598 100644
--- a/util/cutils.c
+++ b/util/cutils.c
@@ -35,6 +35,11 @@
#include <sys/sysctl.h>
#endif
+#ifdef G_OS_WIN32
+#include <pathcch.h>
+#include <wchar.h>
+#endif
+
#include "qemu/ctype.h"
#include "qemu/cutils.h"
#include "qemu/error-report.h"
@@ -1074,31 +1079,52 @@ char *get_relocated_path(const char *dir)
/* Fail if qemu_init_exec_dir was not called. */
assert(exec_dir[0]);
- if (!starts_with_prefix(dir) || !starts_with_prefix(bindir)) {
- return g_strdup(dir);
- }
result = g_string_new(exec_dir);
+ g_string_append(result, "/qemu-bundle");
+ if (access(result->str, R_OK) == 0) {
+#ifdef G_OS_WIN32
+ size_t size = mbsrtowcs(NULL, &dir, 0, &(mbstate_t){0}) + 1;
+ PWSTR wdir = g_new(WCHAR, size);
+ mbsrtowcs(wdir, &dir, size, &(mbstate_t){0});
+
+ PCWSTR wdir_skipped_root;
+ PathCchSkipRoot(wdir, &wdir_skipped_root);
+
+ size = wcsrtombs(NULL, &wdir_skipped_root, 0, &(mbstate_t){0});
+ char *cursor = result->str + result->len;
+ g_string_set_size(result, result->len + size);
+ wcsrtombs(cursor, &wdir_skipped_root, size + 1, &(mbstate_t){0});
+ g_free(wdir);
+#else
+ g_string_append(result, dir);
+#endif
+ } else if (!starts_with_prefix(dir) || !starts_with_prefix(bindir)) {
+ g_string_assign(result, dir);
+ } else {
+ g_string_assign(result, exec_dir);
+
+ /* Advance over common components. */
+ len_dir = len_bindir = prefix_len;
+ do {
+ dir += len_dir;
+ bindir += len_bindir;
+ dir = next_component(dir, &len_dir);
+ bindir = next_component(bindir, &len_bindir);
+ } while (len_dir && len_dir == len_bindir && !memcmp(dir, bindir, len_dir));
+
+ /* Ascend from bindir to the common prefix with dir. */
+ while (len_bindir) {
+ bindir += len_bindir;
+ g_string_append(result, "/..");
+ bindir = next_component(bindir, &len_bindir);
+ }
- /* Advance over common components. */
- len_dir = len_bindir = prefix_len;
- do {
- dir += len_dir;
- bindir += len_bindir;
- dir = next_component(dir, &len_dir);
- bindir = next_component(bindir, &len_bindir);
- } while (len_dir && len_dir == len_bindir && !memcmp(dir, bindir, len_dir));
-
- /* Ascend from bindir to the common prefix with dir. */
- while (len_bindir) {
- bindir += len_bindir;
- g_string_append(result, "/..");
- bindir = next_component(bindir, &len_bindir);
+ if (*dir) {
+ assert(G_IS_DIR_SEPARATOR(dir[-1]));
+ g_string_append(result, dir - 1);
+ }
}
- if (*dir) {
- assert(G_IS_DIR_SEPARATOR(dir[-1]));
- g_string_append(result, dir - 1);
- }
return g_string_free(result, false);
}
diff --git a/util/meson.build b/util/meson.build
index 8cce8f8968..5e282130df 100644
--- a/util/meson.build
+++ b/util/meson.build
@@ -23,6 +23,7 @@ util_ss.add(when: 'CONFIG_WIN32', if_true: files('event_notifier-win32.c'))
util_ss.add(when: 'CONFIG_WIN32', if_true: files('oslib-win32.c'))
util_ss.add(when: 'CONFIG_WIN32', if_true: files('qemu-thread-win32.c'))
util_ss.add(when: 'CONFIG_WIN32', if_true: winmm)
+util_ss.add(when: 'CONFIG_WIN32', if_true: pathcch)
util_ss.add(files('envlist.c', 'path.c', 'module.c'))
util_ss.add(files('host-utils.c'))
util_ss.add(files('bitmap.c', 'bitops.c'))
diff --git a/util/module.c b/util/module.c
index 6bb4ad915a..8ddb0e18f5 100644
--- a/util/module.c
+++ b/util/module.c
@@ -274,7 +274,6 @@ bool module_load_one(const char *prefix, const char *lib_name, bool mayfail)
dirs[n_dirs++] = g_strdup_printf("%s", search_dir);
}
dirs[n_dirs++] = get_relocated_path(CONFIG_QEMU_MODDIR);
- dirs[n_dirs++] = g_strdup(qemu_get_exec_dir());
#ifdef CONFIG_MODULE_UPGRADES
version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION),