Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use HTTPS by default #381

Merged
merged 2 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions grizzly/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,9 @@ def __init__(self):
f" (default: '--test-limit' + {TIMEOUT_DELAY}s)",
)
self.launcher_grp.add_argument(
"--use-https",
"--use-http",
action="store_true",
help="Enable HTTPS. (default: %(default)s)",
help="Use HTTP instead of HTTPS.",
)
self.launcher_grp.add_argument(
"--version",
Expand Down
8 changes: 6 additions & 2 deletions grizzly/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,8 @@ def main(args):
else:
relaunch = args.relaunch

if args.use_https:
if not args.use_http:
certs = CertificateBundle.create()
LOG.info("HTTPS enabled")

LOG.debug("initializing the Target %r", args.platform)
target = load_plugin(args.platform, "grizzly_targets", Target)(
Expand All @@ -88,6 +87,11 @@ def main(args):
target.process_assets()
adapter.monitor = target.monitor

if certs and not target.https():
LOG.warning("Target does not support HTTPS, using HTTP")
certs.cleanup()
certs = None

LOG.debug("initializing the Reporter")
if args.fuzzmanager:
reporter = FuzzManagerReporter(args.tool or f"grizzly-{adapter.name}")
Expand Down
9 changes: 7 additions & 2 deletions grizzly/reduce/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -824,9 +824,8 @@ def main(cls, args):
args.repeat = max(args.min_crashes, args.repeat)
relaunch = min(args.relaunch, args.repeat)

if args.use_https or any(x.https for x in testcases):
if not args.use_http:
certs = CertificateBundle.create()
LOG.info("HTTPS enabled")

LOG.debug("initializing the Target")
target = load_plugin(args.platform, "grizzly_targets", Target)(
Expand All @@ -850,6 +849,12 @@ def main(cls, args):
# prioritize specified assets over included
target.assets.add_batch(args.asset)
target.process_assets()

if certs and not target.https():
LOG.warning("Target does not support HTTPS, using HTTP")
certs.cleanup()
certs = None

LOG.debug("starting sapphire server")
# launch HTTP server used to serve test cases
with Sapphire(auto_close=1, timeout=timeout, certs=certs) as server:
Expand Down
56 changes: 49 additions & 7 deletions grizzly/reduce/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from pytest import mark, raises

from ..common.storage import TestCase, TestCaseLoadFailure
from ..common.utils import Exit
from ..target import AssetManager, TargetLaunchError, TargetLaunchTimeout
from ..common.utils import ConfigError, Exit
from ..target import AssetManager, Target, TargetLaunchError, TargetLaunchTimeout
from . import ReduceManager
from .args import ReduceArgs, ReduceFuzzManagerIDArgs, ReduceFuzzManagerIDQualityArgs
from .exceptions import GrizzlyReduceBaseException
Expand Down Expand Up @@ -93,15 +93,15 @@ def test_args_04(tmp_path):
KeyboardInterrupt,
None,
{},
Exit.ERROR,
Exit.ABORT,
True,
),
(
"grizzly.reduce.core.load_plugin",
GrizzlyReduceBaseException(""),
GrizzlyReduceBaseException("", 999),
None,
{},
Exit.ERROR,
999,
False,
),
(
Expand All @@ -128,6 +128,14 @@ def test_args_04(tmp_path):
Exit.ARGS,
False,
),
(
"grizzly.reduce.core.ReplayManager.load_testcases",
ConfigError("", 999),
None,
{},
999,
False,
),
],
)
def test_main_exit(
Expand All @@ -140,18 +148,22 @@ def test_main_exit(

if use_sig:
sig = tmp_path / "fake.sig"
sig.write_text("{}")
sig.write_text('{"symptoms": [{"address": "0", "type": "crashAddress"}]}')
sig.with_suffix(".metadata").write_text('{"shortDescription": "foo"}')
else:
sig = None

(tmp_path / "test.html").touch()
# setup args
args = mocker.Mock(
ignore=["fake"],
input="test",
input=(tmp_path / "test.html"),
min_crashes=1,
relaunch=1,
repeat=1,
sig=sig,
test_index=None,
timeout=10,
**kwargs
)

Expand Down Expand Up @@ -205,3 +217,33 @@ def test_main_launch_error(mocker, exc_type):
assert report is exc_obj.report
else:
assert reporter.return_value.submit.call_count == 0


@mark.parametrize("https_supported", [True, False])
def test_main_https_support(mocker, tmp_path, https_supported):
"""test ReduceManager.main() - Target HTTPS support"""
mocker.patch("grizzly.reduce.core.FuzzManagerReporter", autospec=True)
mocker.patch("grizzly.reduce.core.ReduceManager.run", autospec=True, return_value=0)
mocker.patch("grizzly.reduce.core.ReductionStatus", autospec=True)
mocker.patch("grizzly.reduce.core.Sapphire", autospec=True)
(tmp_path / "test.html").touch()
# setup args
args = mocker.Mock(
ignore=["fake"],
input=tmp_path / "test.html",
min_crashes=1,
relaunch=1,
repeat=1,
sig=None,
test_index=None,
use_http=False,
time_limit=1,
timeout=1,
)

target_cls = mocker.MagicMock(spec_set=Target)
target = target_cls.return_value
target.https.return_value = https_supported
mocker.patch("grizzly.reduce.core.load_plugin", return_value=target_cls)
assert ReduceManager.main(args) == 0
assert target.https.call_count == 1
8 changes: 6 additions & 2 deletions grizzly/replay/replay.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,9 +631,8 @@ def main(cls, args):
args.min_crashes,
relaunch,
)
if args.use_https or any(x.https for x in testcases):
if not args.use_http:
certs = CertificateBundle.create()
LOG.info("HTTPS enabled")
LOG.debug("initializing the Target")
target = load_plugin(args.platform, "grizzly_targets", Target)(
args.binary,
Expand All @@ -656,6 +655,11 @@ def main(cls, args):
target.assets.add_batch(args.asset)
target.process_assets()

if certs and not target.https():
LOG.warning("Target does not support HTTPS, using HTTP")
certs.cleanup()
certs = None

LOG.debug("starting sapphire server")
# launch HTTP server used to serve test cases
with Sapphire(auto_close=1, timeout=timeout, certs=certs) as server:
Expand Down
28 changes: 28 additions & 0 deletions grizzly/replay/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,3 +443,31 @@ def test_main_07(mocker, server, tmp_path):
assert target.assets.add.call_count == 0
assert target.assets.is_empty.call_count == 1
assert reporter.return_value.submit.call_count == 1


@mark.parametrize("https_supported", [True, False])
def test_main_08(mocker, tmp_path, https_supported):
"""test ReplayManager.main() - Target HTTPS support"""
(tmp_path / "test.html").touch()
args = mocker.MagicMock(
adapter="fake",
binary=Path("bin"),
input=tmp_path / "test.html",
fuzzmanager=False,
launch_attempts=1,
min_crashes=1,
relaunch=1,
repeat=1,
sig=None,
use_http=False,
time_limit=1,
timeout=1,
)

target_cls = mocker.MagicMock(spec_set=Target)
target = target_cls.return_value
target.https.return_value = https_supported
mocker.patch("grizzly.replay.replay.load_plugin", return_value=target_cls)
mocker.patch("grizzly.replay.replay.ReplayManager.run", return_value=[])
assert ReplayManager.main(args) == Exit.FAILURE
assert target.https.call_count == 1
19 changes: 15 additions & 4 deletions grizzly/target/puppet_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from time import sleep, time

from ffpuppet import BrowserTimeoutError, Debugger, FFPuppet, LaunchError, Reason
from ffpuppet.helpers import certutil_available, certutil_find
from ffpuppet.sanitizer_util import SanitizerOptions
from prefpicker import PrefPicker
from psutil import AccessDenied, NoSuchProcess, Process, process_iter, wait_procs
Expand Down Expand Up @@ -85,14 +86,23 @@ class PuppetTarget(Target):
__slots__ = ("use_valgrind", "_debugger", "_extension", "_prefs", "_puppet")

def __init__(self, binary, launch_timeout, log_limit, memory_limit, **kwds):
certs = kwds.pop("certs", None)
# only pass certs to FFPuppet if certutil is available
# otherwise certs can't be used
if certs and not certutil_available(certutil_find(binary)):
LOG.warning("HTTPS support requires NSS certutil.")
certs = None

super().__init__(
binary,
launch_timeout,
log_limit,
memory_limit,
assets=kwds.pop("assets", None),
certs=kwds.pop("certs", None),
certs=certs,
)
self._https = certs is not None

# TODO: clean up handling debuggers
self._debugger = Debugger.NONE
if kwds.pop("pernosco", False):
Expand All @@ -112,9 +122,7 @@ def __init__(self, binary, launch_timeout, log_limit, memory_limit, **kwds):
working_path=str(grz_tmp("target")),
)
if kwds:
LOG.warning(
"PuppetTarget ignoring unsupported arguments: %s", ", ".join(kwds)
)
LOG.debug("PuppetTarget ignoring unsupported kwargs: %s", ", ".join(kwds))

def _cleanup(self):
# prevent parallel calls to FFPuppet.close() and/or FFPuppet.clean_up()
Expand Down Expand Up @@ -223,6 +231,9 @@ def handle_hang(self, ignore_idle=True, ignore_timeout=False):
self.close()
return was_idle

def https(self):
return self._https

def dump_coverage(self, timeout=5):
if system() != "Linux":
LOG.debug("dump_coverage() only supported on Linux")
Expand Down
6 changes: 6 additions & 0 deletions grizzly/target/target.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class Target(metaclass=ABCMeta):

__slots__ = (
"_assets",
"_https",
"_lock",
"_monitor",
"binary",
Expand All @@ -74,6 +75,7 @@ def __init__(
assert assets is None or isinstance(assets, AssetManager)
assert certs is None or isinstance(certs, CertificateBundle)
self._assets = assets if assets else AssetManager(base_path=grz_tmp("target"))
self._https = False
self._lock = Lock()
self._monitor = None
self.binary = binary
Expand Down Expand Up @@ -136,6 +138,10 @@ def filtered_environ(self):
def handle_hang(self, ignore_idle=True, ignore_timeout=False):
pass

@abstractmethod
def https(self):
pass

# TODO: move to monitor?
def is_idle(self, _threshold):
LOG.debug("Target.is_idle() not implemented! returning False")
Expand Down
27 changes: 27 additions & 0 deletions grizzly/target/test_puppet_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from ffpuppet import BrowserTerminatedError, BrowserTimeoutError, Debugger, Reason
from pytest import mark, raises

from ..common.utils import CertificateBundle
from .puppet_target import PuppetTarget
from .target import AssetManager, Result, TargetLaunchError, TargetLaunchTimeout

Expand All @@ -27,6 +28,7 @@ def test_puppet_target_01(mocker, tmp_path):
assert target.log_limit == 25
assert target.memory_limit == 5000
assert target.check_result([]) == Result.NONE
assert not target.https()
assert target.log_size() == 1124
fake_ffp.return_value.log_length.assert_any_call("stderr")
fake_ffp.return_value.log_length.assert_any_call("stdout")
Expand Down Expand Up @@ -473,3 +475,28 @@ def test_puppet_target_14(mocker, tmp_path):
fake_file.touch()
with PuppetTarget(fake_file, 300, 25, 5000) as target:
target.dump_coverage()


@mark.parametrize(
"certutil, certs",
[
# certutil and cert bundle available
(True, True),
# missing certutil
(False, True),
# no cert bundle
(True, False),
],
)
def test_puppet_target_15(mocker, tmp_path, certutil, certs):
"""test PuppetTarget - HTTPS support"""
mocker.patch(
"grizzly.target.puppet_target.certutil_available", return_value=certutil
)

fake_file = tmp_path / "fake"
fake_file.touch()

certs_bundle = mocker.Mock(spec_set=CertificateBundle) if certs else None
with PuppetTarget(fake_file, 300, 25, 5000, certs=certs_bundle) as target:
assert target.https() == (certutil and certs)
3 changes: 3 additions & 0 deletions grizzly/target/test_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ def create_report(self, is_hang=False):
def handle_hang(self, ignore_idle=True, ignore_timeout=False):
pass

def https(self):
return self._https

def launch(self, location):
pass

Expand Down
15 changes: 15 additions & 0 deletions grizzly/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,18 @@ def test_main_04(
assert target_cls.call_args[-1]["pernosco"] == pernosco
assert target_cls.call_args[-1]["rr"] == rr
assert target_cls.call_args[-1]["valgrind"] == valgrind


def test_main_05(mocker, session_setup):
"""test target does not support https"""
target_cls = session_setup[3]
target_cls.return_value.https.return_value = False
args = mocker.MagicMock(
adapter="fake",
binary=Path("bin"),
use_http=False,
time_limit=1,
timeout=1,
)
assert main(args) == Exit.SUCCESS
assert target_cls.return_value.https.call_count == 1
Loading