Skip to content

Commit e946a72

Browse files
MiraclePtr-protected crashes are not security issues. (#4906)
As of M128, if a bug is marked MiraclePtr Status:PROTECTED, it is not considered a security issue. It should be converted to type:Bug and assigned to the appropriate engineering team as functional issue. This patch moves the MiraclePtr detection logic from `issue_filer.py` to `crash_analyzer.py` and uses it to correctly classify MiraclePtr-protected crashes as non-security issues. Fixed:#4903 Fixed:https://crbug.com/40930527
1 parent da67082 commit e946a72

File tree

7 files changed

+163
-22
lines changed

7 files changed

+163
-22
lines changed

src/clusterfuzz/_internal/crash_analysis/crash_analyzer.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import re
1717

1818
from clusterfuzz._internal.config import local_config
19+
from clusterfuzz._internal.metrics import logs
1920
from clusterfuzz._internal.system import environment
2021

2122
ASSERT_CRASH_ADDRESSES = [
@@ -133,6 +134,14 @@
133134
# Default page size of 4KB.
134135
NULL_DEREFERENCE_BOUNDARY = 0x1000
135136

137+
CHROMIUM_MIRACLEPTR_REGEX = re.compile(r'.*MiraclePtr Status:.+')
138+
139+
MIRACLEPTR_STATUS = {
140+
'PROTECTED': 'MiraclePtr-Protected',
141+
'MANUAL ANALYSIS REQUIRED': 'MiraclePtr-ManualAnalysisRequired',
142+
'NOT PROTECTED': 'MiraclePtr-NotProtected'
143+
}
144+
136145

137146
def address_to_integer(address):
138147
"""Attempt to convert an address from a string (hex) to an integer."""
@@ -268,9 +277,26 @@ def has_signal_for_non_security_bug_type(stacktrace):
268277
return False
269278

270279

280+
def check_miracleptr_status(stacktrace):
281+
"""Look for MiraclePtr status string and return the appropriate label."""
282+
for line in stacktrace.split('\n'):
283+
if CHROMIUM_MIRACLEPTR_REGEX.match(line):
284+
status = line.split(':')[-1].strip()
285+
try:
286+
return MIRACLEPTR_STATUS[status]
287+
except KeyError:
288+
logs.error(f'Unknown MiraclePtr status: {line}')
289+
break
290+
return None
291+
292+
271293
def is_security_issue(crash_stacktrace, crash_type, crash_address):
272294
"""Based on unsymbolized crash parameters, determine whether it has security
273295
consequences or not."""
296+
# MiraclePtr protected crashes are not security issues.
297+
if check_miracleptr_status(crash_stacktrace) == 'MiraclePtr-Protected':
298+
return False
299+
274300
# Stack traces of any type can be manually labelled as a security issue.
275301
if re.search('FuzzerSecurityIssue(Critical|High|Medium|Low)',
276302
crash_stacktrace):

src/clusterfuzz/_internal/issue_management/issue_filer.py

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from clusterfuzz._internal.base import external_users
2020
from clusterfuzz._internal.base import utils
2121
from clusterfuzz._internal.config import local_config
22+
from clusterfuzz._internal.crash_analysis import crash_analyzer
2223
from clusterfuzz._internal.crash_analysis import severity_analyzer
2324
from clusterfuzz._internal.datastore import data_handler
2425
from clusterfuzz._internal.datastore import data_types
@@ -74,13 +75,6 @@
7475
]
7576

7677
STACKFRAME_LINE_REGEX = re.compile(r'\s*#\d+\s+0x[0-9A-Fa-f]+\s*')
77-
CHROMIUM_MIRACLEPTR_REGEX = re.compile(r'.*MiraclePtr Status:.+')
78-
79-
MIRACLEPTR_STATUS = {
80-
'PROTECTED': 'MiraclePtr-Protected',
81-
'MANUAL ANALYSIS REQUIRED': 'MiraclePtr-ManualAnalysisRequired',
82-
'NOT PROTECTED': 'MiraclePtr-NotProtected'
83-
}
8478

8579

8680
def platform_substitution(label, testcase, _):
@@ -317,20 +311,6 @@ def notify_issue_update(testcase, status):
317311
oss_fuzz_github.close_issue(testcase)
318312

319313

320-
def check_miracleptr_status(testcase):
321-
"""Look for MiraclePtr status string and return the appropriate label."""
322-
stacktrace = data_handler.get_stacktrace(testcase)
323-
for line in stacktrace.split('\n'):
324-
if CHROMIUM_MIRACLEPTR_REGEX.match(line):
325-
status = line.split(':')[-1].strip()
326-
try:
327-
return MIRACLEPTR_STATUS[status]
328-
except:
329-
logs.error(f'Unknown MiraclePtr status: {line}')
330-
break
331-
return None
332-
333-
334314
def file_issue(testcase,
335315
issue_tracker,
336316
security_severity=None,
@@ -370,7 +350,8 @@ def file_issue(testcase,
370350
update_issue_impact_labels(testcase, issue, policy)
371351

372352
# Check for MiraclePtr in stacktrace.
373-
miracle_label = check_miracleptr_status(testcase)
353+
stacktrace = data_handler.get_stacktrace(testcase)
354+
miracle_label = crash_analyzer.check_miracleptr_status(stacktrace)
374355
if miracle_label:
375356
issue.labels.add(policy.substitution_mapping(miracle_label))
376357

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
==1==ERROR: AddressSanitizer: heap-use-after-free on address 0x60f00003b280 at pc 0x7efd4a2a3e03 bp 0x7ffd1ed50680 sp 0x7ffd1ed50678
2+
READ of size 8 at 0x60f00003b280 thread T0
3+
#0 0x7efd4a2a3e02 in function_a() src/a.cc:1:1
4+
#1 0x7efd4a29f60e in function_b() src/b.cc:1:1
5+
6+
MiraclePtr Status: MANUAL ANALYSIS REQUIRED
7+
8+
0x60f00003b280 is located 16 bytes inside of 112-byte region [0x60f00003b270,0x60f00003b2e0)
9+
freed by thread T0 here:
10+
#0 0x7efd42e32fdb in __interceptor_free
11+
#1 0x7efd4a19be58 in function_c() src/c.cc:1:1
12+
previously allocated by thread T0 here:
13+
#0 0x7efd42e332fb in __interceptor_malloc
14+
#1 0x7efd476d64aa in function_d() src/d.cc:1:1
15+
16+
SUMMARY: AddressSanitizer: heap-use-after-free src/a.cc:1:1 in function_a()
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
==1==ERROR: AddressSanitizer: heap-use-after-free on address 0x60f00003b280 at pc 0x7efd4a2a3e03 bp 0x7ffd1ed50680 sp 0x7ffd1ed50678
2+
READ of size 8 at 0x60f00003b280 thread T0
3+
#0 0x7efd4a2a3e02 in function_a() src/a.cc:1:1
4+
#1 0x7efd4a29f60e in function_b() src/b.cc:1:1
5+
6+
MiraclePtr Status: NOT PROTECTED
7+
8+
0x60f00003b280 is located 16 bytes inside of 112-byte region [0x60f00003b270,0x60f00003b2e0)
9+
freed by thread T0 here:
10+
#0 0x7efd42e32fdb in __interceptor_free
11+
#1 0x7efd4a19be58 in function_c() src/c.cc:1:1
12+
previously allocated by thread T0 here:
13+
#0 0x7efd42e332fb in __interceptor_malloc
14+
#1 0x7efd476d64aa in function_d() src/d.cc:1:1
15+
16+
SUMMARY: AddressSanitizer: heap-use-after-free src/a.cc:1:1 in function_a()
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
==1==ERROR: AddressSanitizer: heap-use-after-free on address 0x60f00003b280 at pc 0x7efd4a2a3e03 bp 0x7ffd1ed50680 sp 0x7ffd1ed50678
2+
READ of size 8 at 0x60f00003b280 thread T0
3+
#0 0x7efd4a2a3e02 in function_a() src/a.cc:1:1
4+
#1 0x7efd4a29f60e in function_b() src/b.cc:1:1
5+
6+
MiraclePtr Status: PROTECTED
7+
8+
0x60f00003b280 is located 16 bytes inside of 112-byte region [0x60f00003b270,0x60f00003b2e0)
9+
freed by thread T0 here:
10+
#0 0x7efd42e32fdb in __interceptor_free
11+
#1 0x7efd4a19be58 in function_c() src/c.cc:1:1
12+
previously allocated by thread T0 here:
13+
#0 0x7efd42e332fb in __interceptor_malloc
14+
#1 0x7efd476d64aa in function_d() src/d.cc:1:1
15+
16+
SUMMARY: AddressSanitizer: heap-use-after-free src/a.cc:1:1 in function_a()
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
==1==ERROR: AddressSanitizer: heap-use-after-free on address 0x60f00003b280 at pc 0x7efd4a2a3e03 bp 0x7ffd1ed50680 sp 0x7ffd1ed50678
2+
READ of size 8 at 0x60f00003b280 thread T0
3+
#0 0x7efd4a2a3e02 in function_a() src/a.cc:1:1
4+
#1 0x7efd4a29f60e in function_b() src/b.cc:1:1
5+
6+
0x60f00003b280 is located 16 bytes inside of 112-byte region [0x60f00003b270,0x60f00003b2e0)
7+
freed by thread T0 here:
8+
#0 0x7efd42e32fdb in __interceptor_free
9+
#1 0x7efd4a19be58 in function_c() src/c.cc:1:1
10+
previously allocated by thread T0 here:
11+
#0 0x7efd42e332fb in __interceptor_malloc
12+
#1 0x7efd476d64aa in function_d() src/d.cc:1:1
13+
14+
SUMMARY: AddressSanitizer: heap-use-after-free src/a.cc:1:1 in function_a()

src/clusterfuzz/_internal/tests/core/crash_analysis/stack_parsing/stack_analyzer_test.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3890,3 +3890,75 @@ def test_missing_libfuzzer_stacktrace(self):
38903890
self._validate_get_crash_data(data, expected_type, expected_address,
38913891
expected_state, expected_stacktrace,
38923892
expected_security_flag, expected_categories)
3893+
3894+
def test_miracle_ptr_protected(self):
3895+
"""Test for a MiraclePtr protected crash."""
3896+
data = self._read_test_data("miracle_ptr_protected.txt")
3897+
expected_type = "Heap-use-after-free\nREAD 8"
3898+
expected_address = "0x60f00003b280"
3899+
expected_state = "function_a\nfunction_b\nfunction_c\n"
3900+
expected_stacktrace = data
3901+
expected_security_flag = False
3902+
3903+
self._validate_get_crash_data(
3904+
data,
3905+
expected_type,
3906+
expected_address,
3907+
expected_state,
3908+
expected_stacktrace,
3909+
expected_security_flag,
3910+
)
3911+
3912+
def test_miracle_ptr_not_protected(self):
3913+
"""Test for a MiraclePtr not protected crash."""
3914+
data = self._read_test_data("miracle_ptr_not_protected.txt")
3915+
expected_type = "Heap-use-after-free\nREAD 8"
3916+
expected_address = "0x60f00003b280"
3917+
expected_state = "function_a\nfunction_b\nfunction_c\n"
3918+
expected_stacktrace = data
3919+
expected_security_flag = True
3920+
3921+
self._validate_get_crash_data(
3922+
data,
3923+
expected_type,
3924+
expected_address,
3925+
expected_state,
3926+
expected_stacktrace,
3927+
expected_security_flag,
3928+
)
3929+
3930+
def test_miracle_ptr_manual_analysis_required(self):
3931+
"""Test for a MiraclePtr crash that requires manual analysis."""
3932+
data = self._read_test_data("miracle_ptr_manual_analysis_required.txt")
3933+
expected_type = "Heap-use-after-free\nREAD 8"
3934+
expected_address = "0x60f00003b280"
3935+
expected_state = "function_a\nfunction_b\nfunction_c\n"
3936+
expected_stacktrace = data
3937+
expected_security_flag = True
3938+
3939+
self._validate_get_crash_data(
3940+
data,
3941+
expected_type,
3942+
expected_address,
3943+
expected_state,
3944+
expected_stacktrace,
3945+
expected_security_flag,
3946+
)
3947+
3948+
def test_miracle_ptr_status_missing(self):
3949+
"""Test for a crash where MiraclePtr status is missing."""
3950+
data = self._read_test_data("miracle_ptr_status_missing.txt")
3951+
expected_type = "Heap-use-after-free\nREAD 8"
3952+
expected_address = "0x60f00003b280"
3953+
expected_state = "function_a\nfunction_b\nfunction_c\n"
3954+
expected_stacktrace = data
3955+
expected_security_flag = True
3956+
3957+
self._validate_get_crash_data(
3958+
data,
3959+
expected_type,
3960+
expected_address,
3961+
expected_state,
3962+
expected_stacktrace,
3963+
expected_security_flag,
3964+
)

0 commit comments

Comments
 (0)