mirror of
https://github.com/taglib/taglib.git
synced 2026-09-07 18:17:00 -04:00
Add fuzz target for FileRef parsing under tests/fuzzing (#1433)
Adds a libFuzzer target parsing arbitrary input through TagLib::FileRef, a format magic dictionary, and a README with build and run instructions. Fully decoupled from the normal build as discussed in #1431.
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
# Fuzzing taglib
|
||||
|
||||
This directory contains a libFuzzer target for taglib's generic parsing entry
|
||||
point. It is intentionally decoupled from the normal CMake build: nothing in
|
||||
the main source tree references it, and it is compiled on demand with the
|
||||
commands below.
|
||||
|
||||
## Target
|
||||
|
||||
`taglib_fileref_fuzzer.cpp` parses arbitrary in-memory input through
|
||||
`TagLib::FileRef` with a `ByteVectorStream`, exercising file type detection
|
||||
plus tag, audio property and complex property (picture) parsing for all
|
||||
supported formats: MP3/ID3v1/ID3v2, FLAC, Ogg Vorbis/Opus/Speex, MP4/M4A,
|
||||
WAV/AIFF, APE/MPC/WavPack, DSF, DSDIFF, Matroska/WebM, Shorten, TrueAudio
|
||||
and the tracker module formats.
|
||||
|
||||
`taglib.dict` is a libFuzzer dictionary of format magic numbers for the
|
||||
supported file types.
|
||||
|
||||
## Building and running
|
||||
|
||||
Build taglib first, for example:
|
||||
|
||||
```
|
||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTING=OFF
|
||||
cmake --build build -j$(nproc)
|
||||
```
|
||||
|
||||
Then compile the fuzz target against it with the libFuzzer and
|
||||
AddressSanitizer flags:
|
||||
|
||||
```
|
||||
clang++ -std=c++17 -g -fsanitize=fuzzer,address -fno-omit-frame-pointer \
|
||||
-I taglib -I taglib/toolkit -I build \
|
||||
tests/fuzzing/taglib_fileref_fuzzer.cpp \
|
||||
build/taglib/libtag.a -lz \
|
||||
-o taglib_fileref_fuzzer
|
||||
```
|
||||
|
||||
Run it over taglib's own test data as a seed corpus (plus a dictionary):
|
||||
|
||||
```
|
||||
./taglib_fileref_fuzzer -dict=tests/fuzzing/taglib.dict tests/data/
|
||||
```
|
||||
|
||||
## OSS-Fuzz
|
||||
|
||||
This target is also built continuously by Google's OSS-Fuzz service for the
|
||||
taglib project, which runs it under AddressSanitizer and
|
||||
UndefinedBehaviorSanitizer with the test data as seed corpus.
|
||||
@@ -0,0 +1,96 @@
|
||||
# Copyright 2026 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Magic numbers and markers for the file formats taglib parses.
|
||||
|
||||
# ID3v2 / ID3v1
|
||||
"ID3"
|
||||
"TAG"
|
||||
"APETAGEX"
|
||||
|
||||
# MPEG audio frame sync
|
||||
"\xFF\xFB"
|
||||
"\xFF\xFA"
|
||||
"\xFF\xF3"
|
||||
"\xFF\xF2"
|
||||
|
||||
# Ogg (Vorbis, Opus, Speex, FLAC-in-Ogg)
|
||||
"OggS"
|
||||
"\x01vorbis"
|
||||
"OpusTags"
|
||||
"\x80Speex"
|
||||
|
||||
# FLAC
|
||||
"fLaC"
|
||||
|
||||
# MP4 / M4A / iTunes
|
||||
"ftyp"
|
||||
"M4A "
|
||||
"mp42"
|
||||
"isom"
|
||||
"moov"
|
||||
"udta"
|
||||
"meta"
|
||||
"ilst"
|
||||
"covr"
|
||||
"free"
|
||||
|
||||
# RIFF / WAV
|
||||
"RIFF"
|
||||
"WAVE"
|
||||
"fmt "
|
||||
"data"
|
||||
"LIST"
|
||||
"ID3 "
|
||||
|
||||
# AIFF
|
||||
"FORM"
|
||||
"AIFF"
|
||||
"AIFC"
|
||||
"COMM"
|
||||
"SSND"
|
||||
|
||||
# APE / MPC / WavPack
|
||||
"MAC "
|
||||
"MP+"
|
||||
"wvpk"
|
||||
|
||||
# DSF / DSDIFF
|
||||
"DSD "
|
||||
"FRM8"
|
||||
"DSd "
|
||||
"DSD"
|
||||
|
||||
# Matroska / WebM (EBML)
|
||||
"\x1A\x45\xDF\xA3"
|
||||
"matroska"
|
||||
"webm"
|
||||
"Segment"
|
||||
"Tags"
|
||||
|
||||
# Tracker modules (IT, XM, S3M, MOD)
|
||||
"IMPM"
|
||||
"Extended Module"
|
||||
"SCRM"
|
||||
"M.K."
|
||||
"M!K!"
|
||||
"FLT4"
|
||||
"4CHN"
|
||||
"6CHN"
|
||||
|
||||
# TrueAudio
|
||||
"TTA1"
|
||||
|
||||
# Shorten (ajkg magic)
|
||||
"ajkg"
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2026 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Fuzzes TagLib's generic file type detection and tag/audio-property parsing
|
||||
// over all supported formats (MP3/ID3v2, FLAC, OGG/Vorbis/Opus/Speex, MP4/AAC,
|
||||
// WAV, AIFF, APE, MPC, WavPack, DSF, DSDIFF, tracker formats, ...).
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <audioproperties.h>
|
||||
#include <fileref.h>
|
||||
#include <tag.h>
|
||||
#include <tbytevector.h>
|
||||
#include <tbytevectorstream.h>
|
||||
#include <tpropertymap.h>
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
const TagLib::ByteVector input(reinterpret_cast<const char *>(data),
|
||||
static_cast<unsigned int>(size));
|
||||
TagLib::ByteVectorStream stream(input);
|
||||
{
|
||||
TagLib::FileRef ref(&stream, /*readAudioProperties=*/true,
|
||||
TagLib::AudioProperties::Average);
|
||||
if (!ref.isNull()) {
|
||||
if (ref.tag()) {
|
||||
const TagLib::Tag *tag = ref.tag();
|
||||
// Touch the standard fields to force a full tag parse.
|
||||
(void)tag->title();
|
||||
(void)tag->artist();
|
||||
(void)tag->album();
|
||||
(void)tag->comment();
|
||||
(void)tag->genre();
|
||||
(void)tag->year();
|
||||
(void)tag->track();
|
||||
(void)tag->properties();
|
||||
}
|
||||
// Parse embedded pictures and other complex properties.
|
||||
(void)ref.complexProperties("PICTURE");
|
||||
if (ref.audioProperties()) {
|
||||
const TagLib::AudioProperties *props = ref.audioProperties();
|
||||
(void)props->lengthInSeconds();
|
||||
(void)props->lengthInMilliseconds();
|
||||
(void)props->bitrate();
|
||||
(void)props->sampleRate();
|
||||
(void)props->channels();
|
||||
}
|
||||
}
|
||||
} // FileRef is destroyed before the stream it borrows.
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user