mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
OSS-Fuzz: Add new fuzzer targets pkg Config Resolver
Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>
This commit is contained in:
@@ -67,6 +67,7 @@ add_fuzzer(cmExprParserFuzzer cmExprParserFuzzer.cxx)
|
||||
|
||||
# pkg-config parser fuzzer
|
||||
add_fuzzer(cmPkgConfigParserFuzzer cmPkgConfigParserFuzzer.cxx)
|
||||
add_fuzzer(cmPkgConfigResolverFuzzer cmPkgConfigResolverFuzzer.cxx)
|
||||
|
||||
# JSON parser fuzzer
|
||||
add_fuzzer(cmJSONParserFuzzer cmJSONParserFuzzer.cxx)
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# pkg-config File Dictionary
|
||||
|
||||
# Key-value separators
|
||||
"="
|
||||
":"
|
||||
|
||||
# Variable reference
|
||||
"${"
|
||||
"}"
|
||||
|
||||
# Common keywords
|
||||
"Name"
|
||||
"Description"
|
||||
"Version"
|
||||
"Requires"
|
||||
"Requires.private"
|
||||
"Conflicts"
|
||||
"Libs"
|
||||
"Libs.private"
|
||||
"Cflags"
|
||||
"URL"
|
||||
|
||||
# Common variables
|
||||
"prefix"
|
||||
"exec_prefix"
|
||||
"libdir"
|
||||
"includedir"
|
||||
"datarootdir"
|
||||
"datadir"
|
||||
"sysconfdir"
|
||||
"sharedstatedir"
|
||||
"localstatedir"
|
||||
|
||||
# Common values
|
||||
"/usr"
|
||||
"/usr/local"
|
||||
"/usr/lib"
|
||||
"/usr/include"
|
||||
"-I"
|
||||
"-L"
|
||||
"-l"
|
||||
"-D"
|
||||
"-pthread"
|
||||
|
||||
# Whitespace
|
||||
" "
|
||||
"\x09"
|
||||
"\x0a"
|
||||
"\x0d\x0a"
|
||||
|
||||
# Comments
|
||||
"#"
|
||||
|
||||
# Version operators
|
||||
">="
|
||||
"<="
|
||||
">"
|
||||
"<"
|
||||
"!="
|
||||
|
||||
# Escapes
|
||||
"\\"
|
||||
"\\$"
|
||||
@@ -0,0 +1,100 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
|
||||
/*
|
||||
* Fuzzer for CMake's pkg-config resolver.
|
||||
*
|
||||
* cmPkgConfigParserFuzzer already covers the .pc tokeniser, but it stops at
|
||||
* the raw key/value pairs. Everything downstream of that is untested because
|
||||
* the resolver is what drives its variable-interpolation entry points.
|
||||
*
|
||||
* The resolver is where the interesting work happens: recursive ${var}
|
||||
* expansion, -I/-L/-l fragment splitting, sysroot re-rooting, and parsing
|
||||
* "Requires:" dependency specs with version operators. .pc files come from
|
||||
* whatever is on PKG_CONFIG_PATH, so a hostile or corrupt package drop is a
|
||||
* realistic source of malformed input.
|
||||
*
|
||||
* All three strictness levels run on every input. Strictness is not chosen by
|
||||
* the input -- Strict and Permissive reject files that BestEffort accepts, so
|
||||
* running all three is what reaches the accept/reject paths in
|
||||
* HasRequiredFields() and HasStrictConflicts().
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/optional>
|
||||
|
||||
#include "cmPkgConfigParser.h"
|
||||
#include "cmPkgConfigResolver.h"
|
||||
|
||||
static constexpr size_t kMaxInputSize = 64 * 1024;
|
||||
|
||||
static cmPkgConfigParser ParseInput(uint8_t const* data, size_t size)
|
||||
{
|
||||
// cmPkgConfigParser::Parse takes a non-const buffer (may modify in place)
|
||||
std::vector<char> buffer(data, data + size);
|
||||
|
||||
cmPkgConfigParser parser;
|
||||
parser.Parse(buffer.data(), buffer.size());
|
||||
parser.Finish();
|
||||
parser.ParseComplete();
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
static void Consume(cmPkgConfigResolver const& resolver)
|
||||
{
|
||||
(void)resolver.Name();
|
||||
(void)resolver.Description();
|
||||
(void)resolver.Version();
|
||||
|
||||
// Dependency specs: version operators and the spec grammar.
|
||||
for (auto const& spec : resolver.Requires(false)) {
|
||||
(void)cmPkgConfigResolver::VersionReqString(spec);
|
||||
(void)cmPkgConfigResolver::CheckVersion(spec, "1.2.3");
|
||||
}
|
||||
(void)resolver.Requires(true);
|
||||
(void)resolver.Conflicts();
|
||||
(void)resolver.Provides();
|
||||
|
||||
// Fragment splitting and sysroot re-rooting, public and private.
|
||||
(void)resolver.Cflags(false);
|
||||
(void)resolver.Cflags(true);
|
||||
(void)resolver.Libs(false);
|
||||
(void)resolver.Libs(true);
|
||||
}
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
|
||||
{
|
||||
if (size == 0 || size > kMaxInputSize) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmPkgConfigEnv env;
|
||||
env.SysrootDir = std::string("/fuzz/sysroot");
|
||||
env.TopBuildDir = std::string("/fuzz/build");
|
||||
env.LibDirs = std::vector<std::string>{ "/usr/lib", "/fuzz/lib" };
|
||||
env.SysCflags = std::vector<std::string>{ "/usr/include" };
|
||||
env.SysLibs = std::vector<std::string>{ "/usr/lib" };
|
||||
|
||||
std::string const pcFileDir = "/fuzz/pkgconfig";
|
||||
|
||||
cmPkgConfigParser const parsed = ParseInput(data, size);
|
||||
|
||||
if (auto strict =
|
||||
cmPkgConfigResolver::ResolveStrict(parsed, env, pcFileDir)) {
|
||||
Consume(*strict);
|
||||
}
|
||||
|
||||
if (auto permissive =
|
||||
cmPkgConfigResolver::ResolvePermissive(parsed, env, pcFileDir)) {
|
||||
Consume(*permissive);
|
||||
}
|
||||
|
||||
Consume(cmPkgConfigResolver::ResolveBestEffort(parsed, env, pcFileDir));
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user