aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS1
-rw-r--r--audio/alsaaudio.c10
-rw-r--r--audio/audio.c15
-rw-r--r--audio/audio_int.h2
-rw-r--r--audio/coreaudio.c48
-rw-r--r--audio/jackaudio.c3
-rw-r--r--audio/paaudio.c10
-rw-r--r--hw/audio/sb16.c14
-rw-r--r--tests/qtest/fuzz-sb16-test.c52
-rw-r--r--tests/qtest/meson.build1
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',