Skip to content

Commit

Permalink
feat: fuzz testing PerlParser (intel#3725)
Browse files Browse the repository at this point in the history
Closes intel#3335
  • Loading branch information
joydeep049 authored Jan 17, 2024
1 parent 470e206 commit 40e5180
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 0 deletions.
75 changes: 75 additions & 0 deletions fuzz/fuzz_cpanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Copyright (C) 2023 Intel Corporation
# SPDX-License-Identifier: GPL-3.0-or-later

import sys
import tempfile
from pathlib import Path

import atheris
import atheris_libprotobuf_mutator
from google.protobuf.json_format import MessageToDict

import fuzz.generated.cpanfile_pb2 as cpanfile_pb2
from cve_bin_tool.cvedb import CVEDB
from cve_bin_tool.log import LOGGER

with atheris.instrument_imports():
from cve_bin_tool.parsers.perl import PerlParser

cve_db = CVEDB()
logger = LOGGER.getChild("Fuzz")


def cpanfileBuilder(data, file_path):
# Convert the Protobuf message to a dictionary
json_data = MessageToDict(
data, preserving_proto_field_name=True, including_default_value_fields=True
)

with open(file_path, "w") as f:
# Writing general requirements
for module in json_data.get("general_requirements", []):
f.write(
f'requires "{module.get("name", "")}" => "{module.get("version", "0")}";\n'
)

# Handling 'test' environment
test_deps = json_data.get("test_dependencies", {})
if test_deps:
f.write("\non 'test' => sub {\n")
for module in test_deps.get("test_requirements", []):
f.write(
f' requires "{module.get("name", "")}" => "{module.get("version", "0")}";\n'
)
for module in test_deps.get("test_recommends", []):
f.write(
f' recommends "{module.get("name", "")}" => "{module.get("version", "0")}";\n'
)
f.write("};\n")

# Handling 'develop' environment
develop_deps = json_data.get("develop_dependencies", {})
if develop_deps:
f.write("\non 'develop' => sub {\n")
for module in develop_deps.get("develop_requirements", []):
f.write(
f' requires "{module.get("name", "")}" => "{module.get("version", "0")}";\n'
)
f.write("};\n")


def TestParseData(data):
try:
cpanfileBuilder(data)

perl_parser = PerlParser(cve_db, logger)
perl_parser.run_checker(file_path)

except SystemExit:
return


file_path = str(Path(tempfile.mkdtemp(prefix="cve-bin-tool-")) / "cpanfile")

atheris_libprotobuf_mutator.Setup(sys.argv, TestParseData, proto=cpanfile_pb2.CPANFile)
atheris.Fuzz()
32 changes: 32 additions & 0 deletions fuzz/generated/cpanfile_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions fuzz/proto_files/cpanfile.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (C) 2022 Intel Corporation
// SPDX-License-Identifier: GPL-3.0-or-later

syntax = "proto3";

// Represents a single Perl module requirement.
message ModuleRequirement {
string name = 1; // The name of the module
string version = 2; // The required version of the module
}

// Represents the entire CPAN file.
message CPANFile {
repeated ModuleRequirement general_requirements = 1; // General requirements

// Dependencies specific to the 'test' environment.
message TestDependencies {
repeated ModuleRequirement test_requirements = 1; // Test requirements
repeated ModuleRequirement test_recommends = 2; // Test recommendations
}
TestDependencies test_dependencies = 2;

// Dependencies specific to the 'develop' environment.
message DevelopDependencies {
repeated ModuleRequirement develop_requirements = 1; // Develop requirements
}
DevelopDependencies develop_dependencies = 3;
}

0 comments on commit 40e5180

Please sign in to comment.