Skip to content

Abort in audio_bug triggered in sb16/pl041

The abort bug w.s.t sb16 was reported here, here, here, here, and fixed here

The abort bug w.s.t pl041 is new.

Root Cause Analysis

There exists a path from pl041 to lm4549_write then to AUD_open_out along which as->freq is 0. The audio_validate_settings will fail when (audsettings *)as->freq is 0.

pl041_write(..., offset, ..., ...)
    // offset=0x54, control=0x2c, data=0
    => lm4549_write(&..., control, data)
        // as.freq = data
        AUD_open_out(..., &as)

To fix this issue, we need to guarantee that s->regs.sl2tx is not empty.

More technique details

QEMU version, upstream commit/tag

3e13d8e3/6.0.50

Host and Guest

Ubuntu 18.04 docker/QTest Fuzzer

Stack traces, crash details

A bug was just triggered in AUD_open_out
Save all your work and restart without audio
I am sorry
Context:
==129== ERROR: libFuzzer: deadly signal
    #0 0x5580e371b168 in __sanitizer_print_stack_trace /root/llvm-project/compiler-rt/lib/asan/asan_stack.cpp:86
    #1 0x5580e3675b22 in fuzzer::PrintStackTrace() /root/llvm-project/compiler-rt/lib/fuzzer/FuzzerUtil.cpp:210
    #2 0x5580e3627cc0 in fuzzer::Fuzzer::CrashCallback() (.part.284) /root/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:233
    #3 0x5580e364d89c in fuzzer::Fuzzer::CrashCallback() /root/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:205
    #4 0x5580e364d89c in fuzzer::Fuzzer::StaticCrashSignalCallback() /root/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:204
    #5 0x7fcd5004697f  (/root/qemu/build-oss-fuzz/DEST_DIR/lib/libpthread.so.0+0x1297f)
    #6 0x7fcd4f65dfb6 in raise (/root/qemu/build-oss-fuzz/DEST_DIR/lib/libc.so.6+0x3efb6)
    #7 0x7fcd4f65f920 in abort (/root/qemu/build-oss-fuzz/DEST_DIR/lib/libc.so.6+0x40920)
    #8 0x5580e3915446 in AUD_open_out /root/qemu/build-oss-fuzz/../audio/audio_template.h
    #9 0x5580e3cda4fd in lm4549_write /root/qemu/build-oss-fuzz/../hw/audio/lm4549.c:192:20
    #10 0x5580e3c11566 in pl041_write /root/qemu/build-oss-fuzz/../hw/audio/pl041.c:451:13
    #11 0x5580e476e097 in memory_region_write_accessor /root/qemu/build-oss-fuzz/../softmmu/memory.c:491:5
    #12 0x5580e476da7d in access_with_adjusted_size /root/qemu/build-oss-fuzz/../softmmu/memory.c:552:18
    #13 0x5580e476da7d in memory_region_dispatch_write /root/qemu/build-oss-fuzz/../softmmu/memory.c:1502:16
    #14 0x5580e461bb31 in flatview_write_continue /root/qemu/build-oss-fuzz/../softmmu/physmem.c:2746:23
    #15 0x5580e460e6c7 in flatview_write /root/qemu/build-oss-fuzz/../softmmu/physmem.c:2786:14
    #16 0x5580e460de6c in address_space_write /root/qemu/build-oss-fuzz/../softmmu/physmem.c:2878:18
    #17 0x5580e3762dec in __wrap_qtest_writel /root/qemu/build-oss-fuzz/../tests/qtest/fuzz/qtest_wrappers.c:177:9
    #18 0x5580e375dcea in stateful_fuzz /root/qemu/build-oss-fuzz/../tests/qtest/fuzz/stateful_fuzz.c:402:13
    #19 0x5580e375f460 in LLVMFuzzerTestOneInput /root/qemu/build-oss-fuzz/../tests/qtest/fuzz/fuzz.c:151:5
    #20 0x5580e364e203 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /root/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:603
    #21 0x5580e3651bc8 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) /root/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:509
    #22 0x5580e365397e in fuzzer::Fuzzer::MutateAndTestOne() /root/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:750
    #23 0x5580e3656e07 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, fuzzer::fuzzer_allocator<fuzzer::SizedFile> >&) /root/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:887
    #24 0x5580e363c2b9 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /root/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:908
    #25 0x5580e3627f92 in main /root/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20
    #26 0x7fcd4f640bf6 in __libc_start_main (/root/qemu/build-oss-fuzz/DEST_DIR/lib/libc.so.6+0x21bf6)
    #27 0x5580e3627fe9 in _start (/root/qemu/build-oss-fuzz/DEST_DIR/qemu-fuzz-arm-target-stateful-fuzz-pl041+0x1147fe9)

NOTE: libFuzzer has rudimentary signal handlers.
      Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal

Reproducer steps

#!/bin/bash -x
export QEMU=/root/qemu/build-oss-fuzz/qemu-system-arm
export BUILDROOT=./
cat << EOF | $QEMU \
-machine integratorcp,accel=qtest -qtest stdio -monitor none -serial none \
-display none -nodefaults -qtest stdio
writel 0x1d000054 0x2c000
EOF

Suggested fix

diff --git a/hw/audio/pl041.c b/hw/audio/pl041.c
index 03acd4f..67e331c 100644
--- a/hw/audio/pl041.c
+++ b/hw/audio/pl041.c
@@ -441,6 +441,8 @@ static void pl041_write(void *opaque, hwaddr offset,
         break;
     }
     case PL041_sl1tx:
+        if (s->regs.slfr & SL2TXEMPTY)
+            break;
         s->regs.slfr &= ~SL1TXEMPTY;

         control = (s->regs.sl1tx >> 12) & 0x7F

Contact

Let me know if I need to provide more information.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information