From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,HTML_MESSAGE,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D0140C2B9F4 for ; Wed, 23 Jun 2021 00:25:40 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 22F60610C7 for ; Wed, 23 Jun 2021 00:25:40 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 22F60610C7 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:48868 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lvqi3-0005eP-0S for qemu-devel@archiver.kernel.org; Tue, 22 Jun 2021 20:25:39 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:35000) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lvqhN-0004qo-UA for qemu-devel@nongnu.org; Tue, 22 Jun 2021 20:24:57 -0400 Received: from mail-oi1-x233.google.com ([2607:f8b0:4864:20::233]:43931) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1lvqhL-0001oF-MV for qemu-devel@nongnu.org; Tue, 22 Jun 2021 20:24:57 -0400 Received: by mail-oi1-x233.google.com with SMTP id x196so1366918oif.10 for ; Tue, 22 Jun 2021 17:24:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to; bh=Okk8+VeaPzE6QcQxg7837Q7rxZcL2AUuxE3NcHF6pcs=; b=qcmFJA88iAL9ntSyo4DewBq26BUe4e7wfaKy4G6u/a4cgdHR5J12EZjulPgzJvcxy3 TEMJgb1eX6yKVXC6DYyzfJfPIe+ZdlSBzbQ47UiWhSXlRCxI+fD7JRIA2+0YYebvmPKw wDHS9jVt2QaW/7SxaOZFxBO0ywEK/HK4JrJXdwQw3Oyob2wl8stKBKTDpbmD6EyOwMzE p0/YzpZnxAN0De5JKdxfL64Blhgt8l85oupRLaSzDKJKFEH4I42C3DUWqhD4mVpsXAgg raC0DPxCBL0uhN01MobIOwRgn3pKTHIqC0tmkZUFLiJH6at1SXPO501IA9qlZdECfDYN OPoA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to; bh=Okk8+VeaPzE6QcQxg7837Q7rxZcL2AUuxE3NcHF6pcs=; b=BtiHuadNNAFbUzmZ2riFVb368gaNTyU+OeWayAYG87dWOgN5DkbGcUcUshRrFOWIZy ywvSdUWAa0yUGCf2zPnKIqZtOUo490+ID2yU/eZS3KkW0A9bcyhg4YnRgCammIaueov6 l+qcNVdLIVpRTwxJH4LNbKdbZb6h9cTGgMxKafGSuaSfVLho0/U0GMVixTmokeEzi3O3 aYPf7ArOB/V4yYp35hahfKiHA1KH8IBq/pcsA8JReFNg52S6wA+CzPsBGtpMx17S0uS8 v79YT6QtTfUNIUP2Lz1bJSbL3pc7lrffOcdxOnBlvUl51pVYJLfVorKIqodAjQ7CsvwD bNqg== X-Gm-Message-State: AOAM532XTIzk/jDIBJsZVdYhMGaDhcwwo+YWcIQp8XaWNmAENmYNgYGz ZqdUeQS2hEXnxu1oTI/WCl5wCh2YGPdlpxniIcVTdy/EmkQ= X-Google-Smtp-Source: ABdhPJyTWSdCQF/+DRiMyS0Inuu/k0SviiCtAmZnpKprdNFN6JAPXCLiN/BkLYMoswzCq+XuTgrQqIdCx06YSgbaMDc= X-Received: by 2002:aca:b5c3:: with SMTP id e186mr1043206oif.43.1624407894200; Tue, 22 Jun 2021 17:24:54 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Qiang Liu Date: Wed, 23 Jun 2021 08:24:42 +0800 Message-ID: Subject: [PATCH] hw/audio/sb16: Restrict I/O sampling rate range for command 41h/42h To: qemu-devel@nongnu.org, Gerd Hoffmann , =?UTF-8?Q?Philippe_Mathieu=2DDaud=C3=A9?= Content-Type: multipart/alternative; boundary="00000000000081135705c563ef65" Received-SPF: pass client-ip=2607:f8b0:4864:20::233; envelope-from=cyruscyliu@gmail.com; helo=mail-oi1-x233.google.com X-Spam_score_int: 0 X-Spam_score: -0.1 X-Spam_bar: / X-Spam_report: (-0.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, URI_DOTEDU=1.999 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" --00000000000081135705c563ef65 Content-Type: text/plain; charset="UTF-8" The I/O sampling rate range is enforced to 5000 to 45000HZ according to commit a2cd86a9. Setting I/O sampling rate with command 41h/42h, a guest user can break this assumption and trigger an assertion in audio_calloc via command 0xd4. This patch restricts the I/O sampling rate range for command 41h/42h. Fixes: 85571bc7415 ("audio merge (malc)") Signed-off-by: Qiang Liu --- hw/audio/sb16.c | 31 +++++++++++++++++++------------ tests/qtest/fuzz-sb16-test.c | 17 +++++++++++++++++ 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c index 5cf121f..60f1f75 100644 --- a/hw/audio/sb16.c +++ b/hw/audio/sb16.c @@ -229,6 +229,23 @@ static void continue_dma8 (SB16State *s) control (s, 1); } +static inline int restrict_sampling_rate(int freq) +{ + if (freq < SAMPLE_RATE_MIN) { + qemu_log_mask(LOG_GUEST_ERROR, + "sampling range too low: %d, increasing to %u\n", + freq, SAMPLE_RATE_MIN); + return SAMPLE_RATE_MIN; + } else if (freq > SAMPLE_RATE_MAX) { + qemu_log_mask(LOG_GUEST_ERROR, + "sampling range too high: %d, decreasing to %u\n", + freq, SAMPLE_RATE_MAX); + return SAMPLE_RATE_MAX; + } else { + return freq; + } +} + static void dma_cmd8 (SB16State *s, int mask, int dma_len) { s->fmt = AUDIO_FORMAT_U8; @@ -244,17 +261,7 @@ 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; - } + s->freq = restrict_sampling_rate(s->freq); if (dma_len != -1) { s->block_size = dma_len << s->fmt_stereo; @@ -768,7 +775,7 @@ static void complete (SB16State *s) * and FT2 sets output freq with this (go figure). Compare: * http://homepages.cae.wisc.edu/~brodskye/sb16doc/sb16doc.html#SamplingRate */ - s->freq = dsp_get_hilo (s); + s->freq = restrict_sampling_rate(dsp_get_hilo(s)); ldebug ("set freq %d\n", s->freq); break; diff --git a/tests/qtest/fuzz-sb16-test.c b/tests/qtest/fuzz-sb16-test.c index 51030cd..f47a8bc 100644 --- a/tests/qtest/fuzz-sb16-test.c +++ b/tests/qtest/fuzz-sb16-test.c @@ -37,6 +37,22 @@ static void test_fuzz_sb16_0x91(void) qtest_quit(s); } +/* + * This used to trigger the assert in audio_calloc + * through command 0xd4 + */ +static void test_fuzz_sb16_0xd4(void) +{ + QTestState *s = qtest_init("-M pc -display none " + "-device sb16,audiodev=none " + "-audiodev id=none,driver=none"); + qtest_outb(s, 0x22c, 0x41); + qtest_outb(s, 0x22c, 0x00); + qtest_outb(s, 0x22c, 0x14); + qtest_outb(s, 0x22c, 0xd4); + qtest_quit(s); +} + int main(int argc, char **argv) { const char *arch = qtest_get_arch(); @@ -46,6 +62,7 @@ int main(int argc, char **argv) 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); + qtest_add_func("fuzz/test_fuzz_sb16/d4", test_fuzz_sb16_0xd4); } return g_test_run(); -- 2.7.4 --00000000000081135705c563ef65 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
The I/O sampling rate r= ange is enforced to 5000 to 45000HZ according to
commit a2cd86a9. Setting I/O samp= ling rate with command 41h/42h, a guest
user can break this assumption a= nd trigger an assertion in audio_calloc
via command 0xd4. This patch res= tricts the I/O sampling rate range for
command 41h/42h.

Fixes: 85= 571bc7415 ("audio merge (malc)")
Signed-off-by: Qiang Liu <= cyrusc= yliu@gmail.com>
---
=C2=A0hw/audio/sb16.c =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0| 31 +++++++++++++++++++------------
=C2=A0t= ests/qtest/fuzz-sb16-test.c | 17 +++++++++++++++++
=C2=A02 files changed= , 36 insertions(+), 12 deletions(-)

diff --git a/hw/audio/sb16.c b/h= w/audio/sb16.c
index 5cf121f..60f1f75 100644
--- a/hw/audio/sb16.c+++ b/hw/audio/sb16.c
@@ -229,6 +229,23 @@ static void continue_dma8 (S= B16State *s)
=C2=A0 =C2=A0 =C2=A0control (s, 1);
=C2=A0}

+stat= ic inline int restrict_sampling_rate(int freq)
+{
+ =C2=A0 =C2=A0if (= freq < SAMPLE_RATE_MIN) {
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_log_mask(= LOG_GUEST_ERROR,
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0"sampling range too low: %d, increasing to %u\= n",
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0freq, SAMPLE_RATE_MIN);
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0re= turn SAMPLE_RATE_MIN;
+ =C2=A0 =C2=A0} else if (freq > SAMPLE_RATE_MA= X) {
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_log_mask(LOG_GUEST_ERROR,
+ = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0"sampling range too high: %d, decreasing to %u\n",
+ =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0freq,= SAMPLE_RATE_MAX);
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0return SAMPLE_RATE_MAX;<= br>+ =C2=A0 =C2=A0} else {
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0return freq;
= + =C2=A0 =C2=A0}
+}
+
=C2=A0static void dma_cmd8 (SB16State *s, in= t mask, int dma_len)
=C2=A0{
=C2=A0 =C2=A0 =C2=A0s->fmt =3D AUDIO_= FORMAT_U8;
@@ -244,17 +261,7 @@ static void dma_cmd8 (SB16State *s, int = mask, int dma_len)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int tmp =3D (256 - = s->time_const);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0s->freq =3D (100= 0000 + (tmp / 2)) / tmp;
=C2=A0 =C2=A0 =C2=A0}
- =C2=A0 =C2=A0if (s-&= gt;freq < SAMPLE_RATE_MIN) {
- =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_log_ma= sk(LOG_GUEST_ERROR,
- =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0"sampling range too low: %d, increasing to = %u\n",
- =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0s->freq, SAMPLE_RATE_MIN);
- =C2=A0 =C2=A0 =C2=A0= =C2=A0s->freq =3D SAMPLE_RATE_MIN;
- =C2=A0 =C2=A0} else if (s->f= req > SAMPLE_RATE_MAX) {
- =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_log_mask(L= OG_GUEST_ERROR,
- =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0"sampling range too high: %d, decreasing to %u= \n",
- =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0s->freq, SAMPLE_RATE_MAX);
- =C2=A0 =C2=A0 =C2=A0 = =C2=A0s->freq =3D SAMPLE_RATE_MAX;
- =C2=A0 =C2=A0}
+ =C2=A0 =C2= =A0s->freq =3D restrict_sampling_rate(s->freq);

=C2=A0 =C2=A0 = =C2=A0if (dma_len !=3D -1) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0s->blo= ck_size =3D dma_len << s->fmt_stereo;
@@ -768,7 +775,7 @@ stati= c void complete (SB16State *s)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 * and FT2 sets output freq with this (go figure).=C2=A0 Compare:=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 * http://homepages.cae.wisc.edu/~brodskye/sb16doc/sb16doc.ht= ml#SamplingRate
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 */<= br>- =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0s->freq =3D dsp_get_hilo (= s);
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0s->freq =3D restrict_s= ampling_rate(dsp_get_hilo(s));
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0ldebug ("set freq %d\n", s->freq);
=C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break;

diff --git a/tests/qtest/fuzz-= sb16-test.c b/tests/qtest/fuzz-sb16-test.c
index 51030cd..f47a8bc 100644=
--- a/tests/qtest/fuzz-sb16-test.c
+++ b/tests/qtest/fuzz-sb16-test.= c
@@ -37,6 +37,22 @@ static void test_fuzz_sb16_0x91(void)
=C2=A0 =C2= =A0 =C2=A0qtest_quit(s);
=C2=A0}

+/*
+ * This used to trigger = the assert in audio_calloc
+ * through command 0xd4
+ */
+static v= oid test_fuzz_sb16_0xd4(void)
+{
+ =C2=A0 =C2=A0QTestState *s =3D qte= st_init("-M pc -display none "
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 "-device sb16,audiodev=3Dnone "
+ =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 "-audiodev id=3Dnone,driver=3Dnone");
+ =C2=A0 =C2=A0qt= est_outb(s, 0x22c, 0x41);
+ =C2=A0 =C2=A0qtest_outb(s, 0x22c, 0x00);
= + =C2=A0 =C2=A0qtest_outb(s, 0x22c, 0x14);
+ =C2=A0 =C2=A0qtest_outb(s, = 0x22c, 0xd4);
+ =C2=A0 =C2=A0qtest_quit(s);
+}
+
=C2=A0int main= (int argc, char **argv)
=C2=A0{
=C2=A0 =C2=A0 =C2=A0const char *arch = =3D qtest_get_arch();
@@ -46,6 +62,7 @@ int main(int argc, char **argv)<= br>=C2=A0 =C2=A0 if (strcmp(arch, "i386") =3D=3D 0) {
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0qtest_add_func("fuzz/test_fuzz_sb16/1c"= ;, test_fuzz_sb16_0x1c);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0qtest_add_fun= c("fuzz/test_fuzz_sb16/91", test_fuzz_sb16_0x91);
+ =C2=A0 =C2= =A0 =C2=A0 =C2=A0qtest_add_func("fuzz/test_fuzz_sb16/d4", test_fu= zz_sb16_0xd4);
=C2=A0 =C2=A0 }

=C2=A0 =C2=A0 return g_test_run();=
--
2.7.4
--00000000000081135705c563ef65--