diff options
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | audio/alsaaudio.c | 10 | ||||
-rw-r--r-- | audio/audio.c | 15 | ||||
-rw-r--r-- | audio/audio_int.h | 2 | ||||
-rw-r--r-- | audio/coreaudio.c | 48 | ||||
-rw-r--r-- | audio/jackaudio.c | 3 | ||||
-rw-r--r-- | audio/paaudio.c | 10 | ||||
-rw-r--r-- | hw/audio/sb16.c | 14 | ||||
-rw-r--r-- | tests/qtest/fuzz-sb16-test.c | 52 | ||||
-rw-r--r-- | tests/qtest/meson.build | 1 |
10 files changed, 102 insertions, 54 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 636bf2f..4842cc2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2221,6 +2221,7 @@ F: qapi/audio.json F: tests/qtest/ac97-test.c F: tests/qtest/es1370-test.c F: tests/qtest/intel-hda-test.c +F: tests/qtest/fuzz-sb16-test.c Block layer core M: Kevin Wolf <kwolf@redhat.com> diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index fcc2f62..2b9789e 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -34,6 +34,8 @@ #define AUDIO_CAP "alsa" #include "audio_int.h" +#define DEBUG_ALSA 0 + struct pollhlp { snd_pcm_t *handle; struct pollfd *pfds; @@ -587,16 +589,12 @@ static int alsa_open(bool in, struct alsa_params_req *req, *handlep = handle; - if (obtfmt != req->fmt || - obt->nchannels != req->nchannels || - obt->freq != req->freq) { + if (DEBUG_ALSA || obtfmt != req->fmt || + obt->nchannels != req->nchannels || obt->freq != req->freq) { dolog ("Audio parameters for %s\n", typ); alsa_dump_info(req, obt, obtfmt, apdo); } -#ifdef DEBUG - alsa_dump_info(req, obt, obtfmt, apdo); -#endif return 0; err: diff --git a/audio/audio.c b/audio/audio.c index 534278e..59453ef 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -32,6 +32,7 @@ #include "qapi/qapi-visit-audio.h" #include "qemu/cutils.h" #include "qemu/module.h" +#include "qemu-common.h" #include "sysemu/replay.h" #include "sysemu/runstate.h" #include "ui/qemu-spice.h" @@ -704,7 +705,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size) if (live == hwsamples) { #ifdef DEBUG_OUT - dolog ("%s is full %d\n", sw->name, live); + dolog ("%s is full %zu\n", sw->name, live); #endif return 0; } @@ -994,7 +995,7 @@ static size_t audio_get_avail (SWVoiceIn *sw) } ldebug ( - "%s: get_avail live %d ret %" PRId64 "\n", + "%s: get_avail live %zu ret %" PRId64 "\n", SW_NAME (sw), live, (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame ); @@ -1021,7 +1022,7 @@ static size_t audio_get_free(SWVoiceOut *sw) dead = sw->hw->mix_buf->size - live; #ifdef DEBUG_OUT - dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n", + dolog ("%s: get_free live %zu dead %zu ret %" PRId64 "\n", SW_NAME (sw), live, dead, (((int64_t) dead << 32) / sw->ratio) * sw->info.bytes_per_frame); @@ -2172,6 +2173,14 @@ const char *audio_get_id(QEMUSoundCard *card) } } +const char *audio_application_name(void) +{ + const char *vm_name; + + vm_name = qemu_get_vm_name(); + return vm_name ? vm_name : "qemu"; +} + void audio_rate_start(RateCtl *rate) { memset(rate, 0, sizeof(RateCtl)); diff --git a/audio/audio_int.h b/audio/audio_int.h index 06f0913..6d685e2 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -243,6 +243,8 @@ void *audio_calloc (const char *funcname, int nmemb, size_t size); void audio_run(AudioState *s, const char *msg); +const char *audio_application_name(void); + typedef struct RateCtl { int64_t start_ticks; int64_t bytes_sent; diff --git a/audio/coreaudio.c b/audio/coreaudio.c index 578ec9b..f570e1e 100644 --- a/audio/coreaudio.c +++ b/audio/coreaudio.c @@ -39,7 +39,6 @@ typedef struct coreaudioVoiceOut { int frameSizeSetting; uint32_t bufferCount; UInt32 audioDevicePropertyBufferFrameSize; - AudioStreamBasicDescription outputStreamBasicDescription; AudioDeviceIOProcID ioprocid; bool enabled; } coreaudioVoiceOut; @@ -114,24 +113,6 @@ static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize) framesize); } -static OSStatus coreaudio_get_streamformat(AudioDeviceID id, - AudioStreamBasicDescription *d) -{ - UInt32 size = sizeof(*d); - AudioObjectPropertyAddress addr = { - kAudioDevicePropertyStreamFormat, - kAudioDevicePropertyScopeOutput, - kAudioObjectPropertyElementMaster - }; - - return AudioObjectGetPropertyData(id, - &addr, - 0, - NULL, - &size, - d); -} - static OSStatus coreaudio_set_streamformat(AudioDeviceID id, AudioStreamBasicDescription *d) { @@ -373,6 +354,17 @@ static OSStatus init_out_device(coreaudioVoiceOut *core) OSStatus status; AudioValueRange frameRange; + AudioStreamBasicDescription streamBasicDescription = { + .mBitsPerChannel = core->hw.info.bits, + .mBytesPerFrame = core->hw.info.bytes_per_frame, + .mBytesPerPacket = core->hw.info.bytes_per_frame, + .mChannelsPerFrame = core->hw.info.nchannels, + .mFormatFlags = kLinearPCMFormatFlagIsFloat, + .mFormatID = kAudioFormatLinearPCM, + .mFramesPerPacket = 1, + .mSampleRate = core->hw.info.freq + }; + status = coreaudio_get_voice(&core->outputDeviceID); if (status != kAudioHardwareNoError) { coreaudio_playback_logerr (status, @@ -432,29 +424,16 @@ static OSStatus init_out_device(coreaudioVoiceOut *core) } core->hw.samples = core->bufferCount * core->audioDevicePropertyBufferFrameSize; - /* get StreamFormat */ - status = coreaudio_get_streamformat(core->outputDeviceID, - &core->outputStreamBasicDescription); - if (status == kAudioHardwareBadObjectError) { - return 0; - } - if (status != kAudioHardwareNoError) { - coreaudio_playback_logerr (status, - "Could not get Device Stream properties\n"); - core->outputDeviceID = kAudioDeviceUnknown; - return status; - } - /* set Samplerate */ status = coreaudio_set_streamformat(core->outputDeviceID, - &core->outputStreamBasicDescription); + &streamBasicDescription); if (status == kAudioHardwareBadObjectError) { return 0; } if (status != kAudioHardwareNoError) { coreaudio_playback_logerr (status, "Could not set samplerate %lf\n", - core->outputStreamBasicDescription.mSampleRate); + streamBasicDescription.mSampleRate); core->outputDeviceID = kAudioDeviceUnknown; return status; } @@ -598,7 +577,6 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as, qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610); core->bufferCount = cpdo->has_buffer_count ? cpdo->buffer_count : 4; - core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq; status = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &voice_addr, handle_voice_change, diff --git a/audio/jackaudio.c b/audio/jackaudio.c index 3031c4e..e7de6d5 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -26,7 +26,6 @@ #include "qemu/module.h" #include "qemu/atomic.h" #include "qemu/main-loop.h" -#include "qemu-common.h" #include "audio.h" #define AUDIO_CAP "jack" @@ -412,7 +411,7 @@ static int qjack_client_init(QJackClient *c) snprintf(client_name, sizeof(client_name), "%s-%s", c->out ? "out" : "in", - c->opt->client_name ? c->opt->client_name : qemu_get_vm_name()); + c->opt->client_name ? c->opt->client_name : audio_application_name()); if (c->opt->exact_name) { options |= JackUseExactName; diff --git a/audio/paaudio.c b/audio/paaudio.c index c97b22e..75401d5 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -2,7 +2,6 @@ #include "qemu/osdep.h" #include "qemu/module.h" -#include "qemu-common.h" #include "audio.h" #include "qapi/opts-visitor.h" @@ -463,10 +462,7 @@ static pa_stream *qpa_simple_new ( pa_stream_set_state_callback(stream, stream_state_cb, c); - flags = - PA_STREAM_INTERPOLATE_TIMING - | PA_STREAM_AUTO_TIMING_UPDATE - | PA_STREAM_EARLY_REQUESTS; + flags = PA_STREAM_EARLY_REQUESTS; if (dev) { /* don't move the stream if the user specified a sink/source */ @@ -756,7 +752,6 @@ static int qpa_validate_per_direction_opts(Audiodev *dev, /* common */ static void *qpa_conn_init(const char *server) { - const char *vm_name; PAConnection *c = g_malloc0(sizeof(PAConnection)); QTAILQ_INSERT_TAIL(&pa_conns, c, list); @@ -765,9 +760,8 @@ static void *qpa_conn_init(const char *server) goto fail; } - vm_name = qemu_get_vm_name(); c->context = pa_context_new(pa_threaded_mainloop_get_api(c->mainloop), - vm_name ? vm_name : "qemu"); + audio_application_name()); if (!c->context) { goto fail; } diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c index 8b20700..5cf121f 100644 --- a/hw/audio/sb16.c +++ b/hw/audio/sb16.c @@ -115,6 +115,9 @@ struct SB16State { PortioList portio_list; }; +#define SAMPLE_RATE_MIN 5000 +#define SAMPLE_RATE_MAX 45000 + static void SB_audio_callback (void *opaque, int free); static int magic_of_irq (int irq) @@ -241,6 +244,17 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len) int tmp = (256 - s->time_const); s->freq = (1000000 + (tmp / 2)) / tmp; } + if (s->freq < SAMPLE_RATE_MIN) { + qemu_log_mask(LOG_GUEST_ERROR, + "sampling range too low: %d, increasing to %u\n", + s->freq, SAMPLE_RATE_MIN); + s->freq = SAMPLE_RATE_MIN; + } else if (s->freq > SAMPLE_RATE_MAX) { + qemu_log_mask(LOG_GUEST_ERROR, + "sampling range too high: %d, decreasing to %u\n", + s->freq, SAMPLE_RATE_MAX); + s->freq = SAMPLE_RATE_MAX; + } if (dma_len != -1) { s->block_size = dma_len << s->fmt_stereo; diff --git a/tests/qtest/fuzz-sb16-test.c b/tests/qtest/fuzz-sb16-test.c new file mode 100644 index 0000000..51030cd --- /dev/null +++ b/tests/qtest/fuzz-sb16-test.c @@ -0,0 +1,52 @@ +/* + * QTest fuzzer-generated testcase for sb16 audio device + * + * Copyright (c) 2021 Philippe Mathieu-Daudé <f4bug@amsat.org> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "libqos/libqtest.h" + +/* + * This used to trigger the assert in audio_calloc + * https://bugs.launchpad.net/qemu/+bug/1910603 + */ +static void test_fuzz_sb16_0x1c(void) +{ + QTestState *s = qtest_init("-M q35 -display none " + "-device sb16,audiodev=snd0 " + "-audiodev none,id=snd0"); + qtest_outw(s, 0x22c, 0x41); + qtest_outb(s, 0x22c, 0x00); + qtest_outw(s, 0x22c, 0x1004); + qtest_outw(s, 0x22c, 0x001c); + qtest_quit(s); +} + +static void test_fuzz_sb16_0x91(void) +{ + QTestState *s = qtest_init("-M pc -display none " + "-device sb16,audiodev=none " + "-audiodev id=none,driver=none"); + qtest_outw(s, 0x22c, 0xf141); + qtest_outb(s, 0x22c, 0x00); + qtest_outb(s, 0x22c, 0x24); + qtest_outb(s, 0x22c, 0x91); + qtest_quit(s); +} + +int main(int argc, char **argv) +{ + const char *arch = qtest_get_arch(); + + g_test_init(&argc, &argv, NULL); + + if (strcmp(arch, "i386") == 0) { + qtest_add_func("fuzz/test_fuzz_sb16/1c", test_fuzz_sb16_0x1c); + qtest_add_func("fuzz/test_fuzz_sb16/91", test_fuzz_sb16_0x91); + } + + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index c3a223a..b03e854 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -20,6 +20,7 @@ slow_qtests = { qtests_generic = \ (config_all_devices.has_key('CONFIG_MEGASAS_SCSI_PCI') ? ['fuzz-megasas-test'] : []) + \ (config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \ + (config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \ [ 'cdrom-test', 'device-introspect-test', |