* SCSI fuzzing fix (Mauro)

* pre-install data files in the build directory (Akihiko)
 * SCSI fixes for Mac OS (Mark)
 -----BEGIN PGP SIGNATURE-----
 
 iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmLO3bQUHHBib256aW5p
 QHJlZGhhdC5jb20ACgkQv/vSX3jHroNv5AgAgGe8hGOcqJSzmFgeUJ7UEaauap6E
 fF4zau8Xux7R6pnvPe2FeJ70AlvstFAUoU++7G3linQ+eqnFD7E18KQkfp9qX7jY
 xDFPJRf6JNhwDjxQ2Tp0ShOcm5HkDv4Z4cPlx0T+wfKTlUWCzNEkhVrjOhpDYnSe
 OldsdFjY0sUjZ1R/QNiuQ65aWwOr9gJ07KfakJQMX2YCMun6SO3kB/GtmyecTV3C
 uNAUIdqJLsEbR1ckdMVVmixhtzMPW2R7/vjJkxG8RXUAcDmDHkuKPhWKyZ9a7/hh
 CV8iMQMup6mgT8ndb5DWv551Y+C/rA1bH9U1NkaeQ9RP83CE4a6fpSMiiQ==
 =82zT
 -----END PGP SIGNATURE-----

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>
master
Peter Maydell 2022-07-14 18:14:12 +01:00
commit 285f64fcbf
26 changed files with 348 additions and 113 deletions

View File

@ -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);

View File

@ -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

15
configure vendored
View File

@ -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=

View File

@ -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.

View File

@ -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 = {

View File

@ -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

View File

@ -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(),
};

View File

@ -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"

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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}

View File

@ -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')

View File

@ -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')

View File

@ -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')

View File

@ -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

View File

@ -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 ;;')

View File

@ -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 ;;

View File

@ -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)"

View File

@ -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

View File

@ -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)

View File

@ -8,6 +8,79 @@
#include "qemu/osdep.h"
#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
@ -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();
}

View File

@ -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=")) {

View File

@ -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});
/* 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));
PCWSTR wdir_skipped_root;
PathCchSkipRoot(wdir, &wdir_skipped_root);
/* 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);
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);
}
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);
}

View File

@ -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'))

View File

@ -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),