Skip to content

Commit

Permalink
Move FuzzManager checks to CommonArgs.sanity_check()
Browse files Browse the repository at this point in the history
This provides error messages instead of tracebacks.
It also reduces the number of workarounds needed for testing
and groups more testing together.
  • Loading branch information
tysmith committed Oct 17, 2023
1 parent 85ed9d9 commit 2adfd8b
Show file tree
Hide file tree
Showing 14 changed files with 48 additions and 75 deletions.
13 changes: 13 additions & 0 deletions grizzly/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from pathlib import Path
from platform import system

from .common.fuzzmanager import FM_CONFIG, ProgramConfiguration
from .common.plugins import scan as scan_plugins
from .common.plugins import scan_target_assets
from .common.utils import DEFAULT_TIME_LIMIT, TIMEOUT_DELAY, __version__
Expand Down Expand Up @@ -265,6 +266,18 @@ def sanity_check(self, args):
if not args.binary.is_file():
self.parser.error(f"file not found: '{args.binary!s}'")

# fuzzmanager reporter related checks
if args.fuzzmanager:
if not FM_CONFIG.is_file():
self.parser.error(f"--fuzzmanager: missing '{FM_CONFIG}'")
bin_cfg = Path(f"{args.binary}.fuzzmanagerconf")
if not bin_cfg.is_file():
self.parser.error(f"--fuzzmanager: missing '{bin_cfg}'")
try:
ProgramConfiguration.fromBinary(str(args.binary))
except RuntimeError as exc:
self.parser.error(f"--fuzzmanager, {exc}")

if args.launch_attempts < 1:
self.parser.error("--launch-attempts must be >= 1")

Expand Down
1 change: 1 addition & 0 deletions grizzly/common/fuzzmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from .reporter import Quality
from .utils import grz_tmp

FM_CONFIG = Path.home() / ".fuzzmanagerconf"
LOG = getLogger(__name__)


Expand Down
20 changes: 0 additions & 20 deletions grizzly/common/reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@
from tempfile import TemporaryDirectory
from zipfile import ZIP_DEFLATED, ZipFile

# import FuzzManager utilities
from Collector.Collector import Collector
from fasteners.process_lock import InterProcessLock
from FTB.ProgramConfiguration import ProgramConfiguration
from psutil import disk_usage

from .report import Report
Expand Down Expand Up @@ -166,8 +164,6 @@ def _post_submit(self):


class FuzzManagerReporter(Reporter):
FM_CONFIG = Path.home() / ".fuzzmanagerconf"

__slots__ = ("_extra_metadata", "quality", "tool")

def __init__(self, tool):
Expand All @@ -182,22 +178,6 @@ def __init__(self, tool):
def _post_submit(self):
self._extra_metadata.clear()

@staticmethod
def sanity_check(bin_file):
"""Perform FuzzManager sanity check.
Args:
bin_file (Path): Binary file being tested.
Returns:
None
"""
if not FuzzManagerReporter.FM_CONFIG.is_file():
raise OSError(f"Missing: {FuzzManagerReporter.FM_CONFIG}")
if not Path(f"{bin_file}.fuzzmanagerconf").is_file():
raise OSError(f"Missing: {bin_file}.fuzzmanagerconf")
ProgramConfiguration.fromBinary(str(bin_file))

def add_extra_metadata(self, key, value):
"""Add extra metadata to be reported with any CrashEntrys reported.
Expand Down
25 changes: 1 addition & 24 deletions grizzly/common/test_reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
# pylint: disable=protected-access
from pathlib import Path

from FTB.ProgramConfiguration import ProgramConfiguration
from pytest import mark, raises

from .report import Report
Expand Down Expand Up @@ -133,28 +132,6 @@ def test_filesystem_reporter_04(mocker, tmp_path):
assert any((tmp_path / "dst").glob("test_prefix_logs"))


def test_fuzzmanager_reporter_01(mocker, tmp_path):
"""test FuzzManagerReporter.sanity_check()"""
fake_reporter = mocker.patch("grizzly.common.reporter.ProgramConfiguration")
fake_reporter.fromBinary.return_value = mocker.Mock(spec_set=ProgramConfiguration)
# missing global FM config file
FuzzManagerReporter.FM_CONFIG = tmp_path / "no_file"
with raises(IOError, match="no_file"):
FuzzManagerReporter.sanity_check("fake")
# missing binary FM config file
fake_fmc = tmp_path / ".fuzzmanagerconf"
fake_fmc.touch()
fake_bin = tmp_path / "bin"
fake_bin.touch()
FuzzManagerReporter.FM_CONFIG = fake_fmc
with raises(IOError, match="bin.fuzzmanagerconf"):
FuzzManagerReporter.sanity_check(str(fake_bin))
# success
(tmp_path / "bin.fuzzmanagerconf").touch()
FuzzManagerReporter.sanity_check(str(fake_bin))
assert fake_reporter.fromBinary.call_count == 1


@mark.parametrize(
"tests, frequent, force, sig_cache",
[
Expand All @@ -170,7 +147,7 @@ def test_fuzzmanager_reporter_01(mocker, tmp_path):
(False, False, False, False),
],
)
def test_fuzzmanager_reporter_02(mocker, tmp_path, tests, frequent, force, sig_cache):
def test_fuzzmanager_reporter_01(mocker, tmp_path, tests, frequent, force, sig_cache):
"""test FuzzManagerReporter.submit()"""
mocker.patch("grizzly.common.reporter.Path.cwd", return_value=tmp_path)
mocker.patch("grizzly.common.reporter.getenv", autospec=True, return_value="0")
Expand Down
2 changes: 0 additions & 2 deletions grizzly/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@
def main(args):
configure_logging(args.log_level)
LOG.info("Starting Grizzly (%d)", getpid())
if args.fuzzmanager:
FuzzManagerReporter.sanity_check(args.binary)

if args.headless:
LOG.info("Running browser headless (%s)", args.headless)
Expand Down
12 changes: 0 additions & 12 deletions grizzly/reduce/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,6 @@
import pytest


@pytest.fixture
def tmp_path_fm_config(tmp_path, mocker):
"""Ensure fm config is always read from tmp_path so ~/.fuzzmanagerconf
can't be used by accident.
"""
mocker.patch(
"grizzly.reduce.core.FuzzManagerReporter.FM_CONFIG",
new=str(tmp_path / ".fuzzmanagerconf"),
)
(tmp_path / ".fuzzmanagerconf").touch()


@pytest.fixture
def reporter_sequential_strftime(mocker):
"""Make `strftime` in `FilesystemReporter` return sequential values.
Expand Down
2 changes: 0 additions & 2 deletions grizzly/reduce/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -766,8 +766,6 @@ def main(cls, args):
# pylint: disable=too-many-return-statements
configure_logging(args.log_level)
setlocale(LC_ALL, "")
if args.fuzzmanager:
FuzzManagerReporter.sanity_check(args.binary)

LOG.info("Starting Grizzly Reduce")

Expand Down
5 changes: 1 addition & 4 deletions grizzly/reduce/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@
from .args import ReduceArgs, ReduceFuzzManagerIDArgs, ReduceFuzzManagerIDQualityArgs
from .exceptions import GrizzlyReduceBaseException

pytestmark = mark.usefixtures(
"tmp_path_fm_config",
"tmp_path_status_db_reduce",
)
pytestmark = mark.usefixtures("tmp_path_status_db_reduce")


def test_args_01(capsys, tmp_path, mocker):
Expand Down
5 changes: 1 addition & 4 deletions grizzly/reduce/test_main_fm.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
from ..common.utils import Exit
from .crash import main as crash_main

pytestmark = mark.usefixtures(
"tmp_path_fm_config",
"tmp_path_status_db_reduce",
)
pytestmark = mark.usefixtures("tmp_path_status_db_reduce")


@mark.parametrize(
Expand Down
1 change: 0 additions & 1 deletion grizzly/reduce/test_reduce.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
LOG = getLogger(__name__)
pytestmark = mark.usefixtures(
"reporter_sequential_strftime",
"tmp_path_fm_config",
"tmp_path_status_db_reduce",
)

Expand Down
1 change: 0 additions & 1 deletion grizzly/reduce/test_strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
LOG = getLogger(__name__)
pytestmark = mark.usefixtures(
"reporter_sequential_strftime",
"tmp_path_fm_config",
"tmp_path_status_db_reduce",
)

Expand Down
3 changes: 0 additions & 3 deletions grizzly/replay/replay.py
Original file line number Diff line number Diff line change
Expand Up @@ -579,9 +579,6 @@ def run(
@classmethod
def main(cls, args):
configure_logging(args.log_level)
if args.fuzzmanager:
FuzzManagerReporter.sanity_check(args.binary)

LOG.info("Starting Grizzly Replay")

if args.headless:
Expand Down
31 changes: 31 additions & 0 deletions grizzly/test_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ def test_common_args_02(capsys, mocker, args, msg, idx):
)
def test_common_args_03(capsys, mocker, tmp_path, args, msg, targets):
"""test CommonArgs.parse_args()"""
fm_config = tmp_path / ".fuzzmanagerconf"
fm_config.touch()
mocker.patch("grizzly.args.FM_CONFIG", fm_config)
mocker.patch("grizzly.args.ProgramConfiguration", autospec=True)
mocker.patch("grizzly.args.scan_plugins", autospec=True, return_value=targets)
mocker.patch(
"grizzly.args.scan_target_assets",
Expand All @@ -132,6 +136,7 @@ def test_common_args_03(capsys, mocker, tmp_path, args, msg, targets):
mocker.patch("grizzly.args.system", autospec=True, return_value="foo")
fake_bin = tmp_path / "fake.bin"
fake_bin.touch()
fake_bin.with_suffix(fake_bin.suffix + ".fuzzmanagerconf").touch()
with raises(SystemExit):
CommonArgs().parse_args(argv=[str(fake_bin)] + args)
assert msg in capsys.readouterr()[-1]
Expand Down Expand Up @@ -160,6 +165,32 @@ def test_common_args_05(mocker):
assert CommonArgs.is_headless()


def test_common_args_06(capsys, mocker, tmp_path):
"""test CommonArgs fuzzmanager checks"""
fake_bin = tmp_path / "bin.exe"
fake_bin.touch()
bin_config = tmp_path / "bin.exe.fuzzmanagerconf"
fm_config = tmp_path / ".fuzzmanagerconf"
mocker.patch("grizzly.args.FM_CONFIG", fm_config)

# missing system .fuzzmanagerconf
with raises(SystemExit):
CommonArgs().parse_args(argv=[str(fake_bin), "--fuzzmanager"])
assert f"--fuzzmanager: missing '{fm_config}'" in capsys.readouterr()[-1]

fm_config.touch()
# missing binary.fuzzmanagerconf
with raises(SystemExit):
CommonArgs().parse_args(argv=[str(fake_bin), "--fuzzmanager"])
assert f"--fuzzmanager: missing '{bin_config}'" in capsys.readouterr()[-1]

bin_config.touch()
# bad binary.fuzzmanagerconf
with raises(SystemExit):
CommonArgs().parse_args(argv=[str(fake_bin), "--fuzzmanager"])
assert '"product" in binary configuration file' in capsys.readouterr()[-1]


@mark.parametrize(
"extra_args, results",
[
Expand Down
2 changes: 0 additions & 2 deletions grizzly/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@
(0, ["--ignore", "timeout"]),
# headless
(0, ["--headless"]),
# FuzzManager reporter
(0, ["--fuzzmanager"]),
# verbose mode
(0, ["--verbose"]),
],
Expand Down

0 comments on commit 2adfd8b

Please sign in to comment.