Skip to content

Commit a2cd86a

Browse files
philmdkraxel
authored andcommitted
hw/audio/sb16: Avoid assertion by restricting I/O sampling rate range
While the SB16 seems to work up to 48000 Hz, the "Sound Blaster Series Hardware Programming Guide" limit the sampling range from 4000 Hz to 44100 Hz (Section 3-9, 3-10: Digitized Sound I/O Programming, tables 3-2 and 3-3). Later, section 6-15 (DSP Commands) is more specific regarding the 41h / 42h registers (Set digitized sound output sampling rate): Valid sampling rates range from 5000 to 45000 Hz inclusive. There is no comment regarding error handling if the register is filled with an out-of-range value. (See also section 3-28 "8-bit or 16-bit Auto-initialize Transfer"). Assume limits are enforced in hardware. This fixes triggering an assertion in audio_calloc(): #1 abort #2 audio_bug audio/audio.c:119:9 #3 audio_calloc audio/audio.c:154:9 #4 audio_pcm_sw_alloc_resources_out audio/audio_template.h:116:15 #5 audio_pcm_sw_init_out audio/audio_template.h:175:11 #6 audio_pcm_create_voice_pair_out audio/audio_template.h:410:9 #7 AUD_open_out audio/audio_template.h:503:14 #8 continue_dma8 hw/audio/sb16.c:216:20 #9 dma_cmd8 hw/audio/sb16.c:276:5 #10 command hw/audio/sb16.c:0 #11 dsp_write hw/audio/sb16.c:949:13 #12 portio_write softmmu/ioport.c:205:13 #13 memory_region_write_accessor softmmu/memory.c:491:5 #14 access_with_adjusted_size softmmu/memory.c:552:18 #15 memory_region_dispatch_write softmmu/memory.c:0:13 #16 flatview_write_continue softmmu/physmem.c:2759:23 #17 flatview_write softmmu/physmem.c:2799:14 #18 address_space_write softmmu/physmem.c:2891:18 #19 cpu_outw softmmu/ioport.c:70:5 [*] http://www.baudline.com/solutions/full_duplex/sb16_pci/index.html OSS-Fuzz Report: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=29174 Fixes: 85571bc ("audio merge (malc)") Buglink: https://bugs.launchpad.net/bugs/1910603 Tested-by: Qiang Liu <[email protected]> Reviewed-by: Qiang Liu <[email protected]> Signed-off-by: Philippe Mathieu-Daudé <[email protected]> Message-Id: <[email protected]> Signed-off-by: Gerd Hoffmann <[email protected]>
1 parent 2833d69 commit a2cd86a

File tree

4 files changed

+68
-0
lines changed

4 files changed

+68
-0
lines changed

MAINTAINERS

+1
Original file line numberDiff line numberDiff line change
@@ -2221,6 +2221,7 @@ F: qapi/audio.json
22212221
F: tests/qtest/ac97-test.c
22222222
F: tests/qtest/es1370-test.c
22232223
F: tests/qtest/intel-hda-test.c
2224+
F: tests/qtest/fuzz-sb16-test.c
22242225

22252226
Block layer core
22262227
M: Kevin Wolf <[email protected]>

hw/audio/sb16.c

+14
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ struct SB16State {
115115
PortioList portio_list;
116116
};
117117

118+
#define SAMPLE_RATE_MIN 5000
119+
#define SAMPLE_RATE_MAX 45000
120+
118121
static void SB_audio_callback (void *opaque, int free);
119122

120123
static int magic_of_irq (int irq)
@@ -241,6 +244,17 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len)
241244
int tmp = (256 - s->time_const);
242245
s->freq = (1000000 + (tmp / 2)) / tmp;
243246
}
247+
if (s->freq < SAMPLE_RATE_MIN) {
248+
qemu_log_mask(LOG_GUEST_ERROR,
249+
"sampling range too low: %d, increasing to %u\n",
250+
s->freq, SAMPLE_RATE_MIN);
251+
s->freq = SAMPLE_RATE_MIN;
252+
} else if (s->freq > SAMPLE_RATE_MAX) {
253+
qemu_log_mask(LOG_GUEST_ERROR,
254+
"sampling range too high: %d, decreasing to %u\n",
255+
s->freq, SAMPLE_RATE_MAX);
256+
s->freq = SAMPLE_RATE_MAX;
257+
}
244258

245259
if (dma_len != -1) {
246260
s->block_size = dma_len << s->fmt_stereo;

tests/qtest/fuzz-sb16-test.c

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* QTest fuzzer-generated testcase for sb16 audio device
3+
*
4+
* Copyright (c) 2021 Philippe Mathieu-Daudé <[email protected]>
5+
*
6+
* SPDX-License-Identifier: GPL-2.0-or-later
7+
*/
8+
9+
#include "qemu/osdep.h"
10+
#include "libqos/libqtest.h"
11+
12+
/*
13+
* This used to trigger the assert in audio_calloc
14+
* https://bugs.launchpad.net/qemu/+bug/1910603
15+
*/
16+
static void test_fuzz_sb16_0x1c(void)
17+
{
18+
QTestState *s = qtest_init("-M q35 -display none "
19+
"-device sb16,audiodev=snd0 "
20+
"-audiodev none,id=snd0");
21+
qtest_outw(s, 0x22c, 0x41);
22+
qtest_outb(s, 0x22c, 0x00);
23+
qtest_outw(s, 0x22c, 0x1004);
24+
qtest_outw(s, 0x22c, 0x001c);
25+
qtest_quit(s);
26+
}
27+
28+
static void test_fuzz_sb16_0x91(void)
29+
{
30+
QTestState *s = qtest_init("-M pc -display none "
31+
"-device sb16,audiodev=none "
32+
"-audiodev id=none,driver=none");
33+
qtest_outw(s, 0x22c, 0xf141);
34+
qtest_outb(s, 0x22c, 0x00);
35+
qtest_outb(s, 0x22c, 0x24);
36+
qtest_outb(s, 0x22c, 0x91);
37+
qtest_quit(s);
38+
}
39+
40+
int main(int argc, char **argv)
41+
{
42+
const char *arch = qtest_get_arch();
43+
44+
g_test_init(&argc, &argv, NULL);
45+
46+
if (strcmp(arch, "i386") == 0) {
47+
qtest_add_func("fuzz/test_fuzz_sb16/1c", test_fuzz_sb16_0x1c);
48+
qtest_add_func("fuzz/test_fuzz_sb16/91", test_fuzz_sb16_0x91);
49+
}
50+
51+
return g_test_run();
52+
}

tests/qtest/meson.build

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ slow_qtests = {
2020
qtests_generic = \
2121
(config_all_devices.has_key('CONFIG_MEGASAS_SCSI_PCI') ? ['fuzz-megasas-test'] : []) + \
2222
(config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \
23+
(config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \
2324
[
2425
'cdrom-test',
2526
'device-introspect-test',

0 commit comments

Comments
 (0)