Skip to content
Draft
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
12 changes: 12 additions & 0 deletions src/appengine/handlers/fuzzers.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ def apply_fuzzer_changes(self, fuzzer, upload_info):
timeout = self._get_integer_value('timeout')
max_testcases = self._get_integer_value('max_testcases')
external_contribution = request.get('external_contribution', False)
untrusted = request.get('untrusted', False)
differential = request.get('differential', False)
environment_string = request.get('additional_environment_string')
data_bundle_name = request.get('data_bundle_name')
Expand All @@ -193,6 +194,7 @@ def apply_fuzzer_changes(self, fuzzer, upload_info):
fuzzer.sample_testcase = None
fuzzer.console_output = None
fuzzer.external_contribution = bool(external_contribution)
fuzzer.untrusted = bool(untrusted)
fuzzer.differential = bool(differential)
fuzzer.additional_environment_string = environment_string
fuzzer.timestamp = datetime.datetime.now(tz=datetime.timezone.utc).replace(
Expand All @@ -208,6 +210,16 @@ def apply_fuzzer_changes(self, fuzzer, upload_info):
if launcher_script:
fuzzer.launcher_script = launcher_script

if fuzzer.untrusted:
for job_name in jobs:
job = data_types.Job.query(data_types.Job.name == job_name).get()
if not job:
raise helpers.EarlyExitError(f'Job {job_name} not found.', 400)
if job.platform.lower() != 'linux':
raise helpers.EarlyExitError(
f'Untrusted fuzzers can only be run on Linux jobs. '
f'Job "{job_name}" has platform "{job.platform}".', 400)

fuzzer.put()

fuzzer_selection.update_mappings_for_fuzzer(fuzzer)
Expand Down
10 changes: 8 additions & 2 deletions src/appengine/private/components/fuzzers-page/edit-form.html
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,16 @@
</div>
<div class="inline narrow">
<paper-checkbox checked="{{fuzzer.external_contribution}}">External contribution</paper-checkbox>
</div>
<div class="inline narrow">
<paper-checkbox checked="{{fuzzer.untrusted}}">Untrusted</paper-checkbox>
</div>

<!-- TODO: Re-enable after the differential fuzzing is implemented.
<!-- TODO: Re-enable after the differential fuzzing is implemented.
<div class="inline narrow">
<paper-checkbox checked="{{fuzzer.differential}}">Differential fuzzer</paper-checkbox>
-->
</div>
-->
</ajax-dialog>
<iron-ajax
id="ajaxFinish"
Expand Down Expand Up @@ -257,6 +262,7 @@
'max_testcases',
'name',
'timeout',
'untrusted',
],
},
file: Object,
Expand Down
3 changes: 3 additions & 0 deletions src/clusterfuzz/_internal/datastore/data_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,9 @@ class Fuzzer(Model):
# Does it run un-trusted content ? Examples including running live sites.
untrusted_content = ndb.BooleanProperty(default=False)

# Is this fuzzer untrusted? (VRP support)
untrusted = ndb.BooleanProperty(default=False)

# Data bundle name.
data_bundle_name = ndb.StringProperty(default='')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ def test_update_fuzzer(self):
'additional_environment_string': 'args=123',
'data_bundle_name': 'test_bundle',
'external_contribution': True,
'untrusted': False,
'executable_path': 'executable',
'last_edited_by': 'editor@example.com',
'launcher_script': 'launcher',
Expand All @@ -188,3 +189,68 @@ def test_update_fuzzer(self):
'source': 'original@example.com',
'timeout': 30,
})

def test_update_fuzzer_untrusted_success(self):
"""Test updating a fuzzer to untrusted with a Linux job succeeds."""
# Create a Linux job.
job = data_types.Job(name='linux_job', platform='LINUX')
job.put()

fuzzer_name = 'test_fuzzer'
fuzzer = data_types.Fuzzer(
name=fuzzer_name,
jobs=[],
revision=1,
source='original@example.com',
timeout=10,
)
fuzzer.put()

request_payload = {
'csrf_token': form.generate_csrf_token(),
'key': fuzzer.key.id(),
'name': fuzzer_name,
'untrusted': True,
'jobs': ['linux_job'],
}

resp = self.app.post_json('/fuzzers/edit', request_payload)
self.assertEqual(302, resp.status_int) # Redirects to /fuzzers

fuzzer = fuzzer.key.get()
self.assertTrue(fuzzer.untrusted)
self.assertEqual(fuzzer.jobs, ['linux_job'])

def test_update_fuzzer_untrusted_failure_non_linux(self):
"""Test updating a fuzzer to untrusted with a non-Linux job fails."""
# Create a Windows job.
job = data_types.Job(name='windows_job', platform='WINDOWS')
job.put()

fuzzer_name = 'test_fuzzer'
fuzzer = data_types.Fuzzer(
name=fuzzer_name,
jobs=[],
revision=1,
source='original@example.com',
timeout=10,
)
fuzzer.put()

request_payload = {
'csrf_token': form.generate_csrf_token(),
'key': fuzzer.key.id(),
'name': fuzzer_name,
'untrusted': True,
'jobs': ['windows_job'],
}

resp = self.app.post_json(
'/fuzzers/edit', request_payload, expect_errors=True)
self.assertEqual(400, resp.status_int)
self.assertIn('Untrusted fuzzers can only be run on Linux jobs',
resp.normal_body.decode())

# Verify fuzzer was not updated to untrusted.
fuzzer = fuzzer.key.get()
self.assertFalse(fuzzer.untrusted)
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def test_get_config_dict(self):
'revision': 3,
'source': 'author',
'last_edited_by': 'editor',
'untrusted': False,
},
config_dict,
)
Expand Down
Loading