A heap-buffer-overflow has been identified in the lame_copy_inbuffer() function in libmp3lame/lame.c of lame-3.100.
Result of ASAN:
=================================================================
==3447316==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x53200002f0e8 at pc 0x55555568f71d bp 0x7fffffffe0f0 sp 0x7fffffffe0e8
READ of size 2 at 0x53200002f0e8 thread T0
#0 0x55555568f71c in lame_copy_inbuffer /cve/repo/lame-3.100/libmp3lame/lame.c:1856:9
#1 0x555555687934 in lame_encode_buffer_template /cve/repo/lame-3.100/libmp3lame/lame.c
#2 0x555555688f4c in lame_encode_buffer_interleaved /cve/repo/lame-3.100/libmp3lame/lame.c:2008:12
#3 0x555555675d73 in main /cve/harness/lame/fuzzer.cc:180:5
#4 0x155554f791c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#5 0x155554f7928a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#6 0x5555555915d4 in _start (/cve/harness/lame/out/lame_afl_fuzzer+0x3d5d4) (BuildId: 88da4c97acf1f65f18455b62daefd4e567ea8dee)
0x53200002f0e8 is located 1 bytes after 92391-byte region [0x532000018800,0x53200002f0e7)
allocated by thread T0 here:
#0 0x555555672a81 in operator new(unsigned long) (/cve/harness/lame/out/lame_afl_fuzzer+0x11ea81) (BuildId: 88da4c97acf1f65f18455b62daefd4e567ea8dee)
#1 0x555555675878 in std::__new_allocator<unsigned char>::allocate(unsigned long, void const*) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/new_allocator.h:151:27
#2 0x555555675878 in std::allocator_traits<std::allocator<unsigned char>>::allocate(std::allocator<unsigned char>&, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/alloc_traits.h:482:20
#3 0x555555675878 in std::_Vector_base<unsigned char, std::allocator<unsigned char>>::_M_allocate(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:381:20
#4 0x555555675878 in std::_Vector_base<unsigned char, std::allocator<unsigned char>>::_M_create_storage(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:398:33
#5 0x555555675878 in std::_Vector_base<unsigned char, std::allocator<unsigned char>>::_Vector_base(unsigned long, std::allocator<unsigned char> const&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:335:9
#6 0x555555675878 in std::vector<unsigned char, std::allocator<unsigned char>>::vector(unsigned long, std::allocator<unsigned char> const&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:557:9
#7 0x555555675878 in std::vector<unsigned char, std::allocator<unsigned char>> FuzzedDataProvider::ConsumeBytes<unsigned char>(unsigned long, unsigned long) /usr/lib/llvm-19/lib/clang/19/include/fuzzer/FuzzedDataProvider.h:361:18
#8 0x555555675878 in std::vector<unsigned char, std::allocator<unsigned char>> FuzzedDataProvider::ConsumeBytes<unsigned char>(unsigned long) /usr/lib/llvm-19/lib/clang/19/include/fuzzer/FuzzedDataProvider.h:110:10
#9 0x555555675878 in std::vector<unsigned char, std::allocator<unsigned char>> FuzzedDataProvider::ConsumeRemainingBytes<unsigned char>() /usr/lib/llvm-19/lib/clang/19/include/fuzzer/FuzzedDataProvider.h:129:10
#10 0x555555675878 in main /cve/harness/lame/fuzzer.cc:159:47
#11 0x155554f791c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#12 0x155554f7928a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#13 0x5555555915d4 in _start (/cve/harness/lame/out/lame_afl_fuzzer+0x3d5d4) (BuildId: 88da4c97acf1f65f18455b62daefd4e567ea8dee)
SUMMARY: AddressSanitizer: heap-buffer-overflow /cve/repo/lame-3.100/libmp3lame/lame.c:1856:9 in lame_copy_inbuffer
Shadow bytes around the buggy address:
0x53200002ee00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x53200002ee80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x53200002ef00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x53200002ef80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x53200002f000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x53200002f080: 00 00 00 00 00 00 00 00 00 00 00 00 07[fa]fa fa
0x53200002f100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x53200002f180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x53200002f200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x53200002f280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x53200002f300: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==3447316==ABORTING
lame-3.100
#include <stdint.h>
#include <stddef.h>
#include <vector>
#include <stdarg.h>
#include <iostream>
#include <iterator>
#include "fuzzer/FuzzedDataProvider.h"
extern "C" {
#include "lame.h"
}
void null_error_handler(const char *format, va_list ap) {
}
int main(int argc, char **argv) {
std::ios_base::sync_with_stdio(false);
std::cin.tie(NULL);
std::vector<uint8_t> buffer(
(std::istreambuf_iterator<char>(std::cin)),
std::istreambuf_iterator<char>()
);
const uint8_t *Data = buffer.data();
size_t Size = buffer.size();
FuzzedDataProvider provider(Data, Size);
lame_global_flags *gfp = lame_init();
if (gfp == NULL) {
return 0;
}
lame_set_errorf(gfp, null_error_handler);
lame_set_debugf(gfp, null_error_handler);
lame_set_msgf(gfp, null_error_handler);
const int sample_rates[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000 };
lame_set_in_samplerate(gfp, provider.PickValueInArray(sample_rates));
lame_set_num_channels(gfp, provider.ConsumeIntegralInRange<int>(1, 2));
lame_set_brate(gfp, provider.ConsumeIntegralInRange<int>(8, 320));
lame_set_mode(gfp, (MPEG_mode)provider.ConsumeIntegralInRange<int>(0, 4));
lame_set_quality(gfp, provider.ConsumeIntegralInRange<int>(0, 9));
lame_set_VBR(gfp, (vbr_mode)provider.ConsumeIntegralInRange<int>(0, 6));
lame_set_VBR_q(gfp, provider.ConsumeIntegralInRange<int>(0, 9));
lame_set_VBR_mean_bitrate_kbps(gfp, provider.ConsumeIntegralInRange<int>(8, 320));
lame_set_bWriteVbrTag(gfp, 0);
int ret_code = lame_init_params(gfp);
if (ret_code < 0) {
lame_close(gfp);
return 0;
}
std::vector<uint8_t> pcm_bytes = provider.ConsumeRemainingBytes<uint8_t>();
int num_channels = lame_get_num_channels(gfp);
if (pcm_bytes.empty() || num_channels == 0) {
lame_close(gfp);
return 0;
}
short* pcm_buffer = (short*)pcm_bytes.data();
size_t num_shorts = pcm_bytes.size() / sizeof(short);
int actual_samples = num_shorts / num_channels;
if (actual_samples == 0) {
lame_close(gfp);
return 0;
}
int mp3_buffer_size = (int)(1.25 * actual_samples) + 7200;
std::vector<unsigned char> mp3_buffer(mp3_buffer_size);
lame_encode_buffer_interleaved(gfp,
pcm_buffer,
actual_samples,
mp3_buffer.data(),
mp3_buffer.size());
lame_encode_flush(gfp, mp3_buffer.data(), mp3_buffer.size());
lame_close(gfp);
return 0;
}
Usage
_./fuzzer < poc _