|
|
|
(*
|
|
|
|
* Copyright (c) 2018-present, Facebook, Inc.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
|
|
|
*)
|
|
|
|
|
|
|
|
open! IStd
|
|
|
|
|
|
|
|
let update_issues all_issues =
|
|
|
|
let quandary_access_issues = [IssueType.untrusted_buffer_access] in
|
|
|
|
let quandary_alloc_issues =
|
|
|
|
IssueType.[untrusted_heap_allocation; untrusted_variable_length_array]
|
|
|
|
in
|
|
|
|
let inferbo_access_issues =
|
|
|
|
IssueType.
|
|
|
|
[ buffer_overrun_l1
|
|
|
|
; buffer_overrun_l2
|
|
|
|
; buffer_overrun_l3
|
|
|
|
; buffer_overrun_l4
|
|
|
|
; buffer_overrun_l5
|
|
|
|
; buffer_overrun_s2
|
|
|
|
; buffer_overrun_u5 ]
|
|
|
|
in
|
|
|
|
let inferbo_alloc_issues =
|
|
|
|
IssueType.
|
|
|
|
[ inferbo_alloc_is_big
|
|
|
|
; inferbo_alloc_is_zero
|
|
|
|
; inferbo_alloc_is_negative
|
|
|
|
; inferbo_alloc_may_be_big
|
|
|
|
; inferbo_alloc_may_be_negative ]
|
|
|
|
in
|
|
|
|
let is_quandary_access_issue issue =
|
|
|
|
List.mem quandary_access_issues issue.Issue.err_key.err_name ~equal:IssueType.equal
|
|
|
|
in
|
|
|
|
let is_quandary_alloc_issue issue =
|
|
|
|
List.mem quandary_alloc_issues issue.Issue.err_key.err_name ~equal:IssueType.equal
|
|
|
|
in
|
|
|
|
let is_relevant_quandary_issue issue =
|
|
|
|
is_quandary_access_issue issue || is_quandary_alloc_issue issue
|
|
|
|
in
|
|
|
|
let is_inferbo_access_issue issue =
|
|
|
|
List.mem inferbo_access_issues issue.Issue.err_key.err_name ~equal:IssueType.equal
|
|
|
|
in
|
|
|
|
let is_inferbo_alloc_issue issue =
|
|
|
|
List.mem inferbo_alloc_issues issue.Issue.err_key.err_name ~equal:IssueType.equal
|
|
|
|
in
|
|
|
|
let is_relevant_inferbo_issue issue =
|
|
|
|
is_inferbo_access_issue issue || is_inferbo_alloc_issue issue
|
|
|
|
in
|
|
|
|
let quandary_issues, inferBO_issues =
|
|
|
|
List.fold all_issues ~init:([], []) ~f:(fun (q_issues, iBO_issues) issue ->
|
|
|
|
if is_relevant_quandary_issue issue then (issue :: q_issues, iBO_issues)
|
|
|
|
else if is_relevant_inferbo_issue issue then (q_issues, issue :: iBO_issues)
|
|
|
|
else (q_issues, iBO_issues) )
|
|
|
|
in
|
|
|
|
let matching_issues quandary_issue inferbo_issue =
|
|
|
|
let trace_end_match () =
|
|
|
|
let quandary_trace_end = List.last quandary_issue.Issue.err_data.loc_trace in
|
|
|
|
let inferbo_trace_end = List.last inferbo_issue.Issue.err_data.loc_trace in
|
|
|
|
match (quandary_trace_end, inferbo_trace_end) with
|
|
|
|
| Some quandary_trace_elem, Some inferbo_trace_elem ->
|
|
|
|
let q_loc = quandary_trace_elem.lt_loc in
|
|
|
|
let i_loc = inferbo_trace_elem.lt_loc in
|
|
|
|
SourceFile.equal q_loc.file i_loc.file && Int.equal q_loc.line i_loc.line
|
|
|
|
| _ ->
|
|
|
|
false
|
|
|
|
in
|
|
|
|
SourceFile.equal quandary_issue.Issue.proc_location.file inferbo_issue.Issue.proc_location.file
|
|
|
|
&& Int.equal quandary_issue.Issue.proc_location.line inferbo_issue.Issue.proc_location.line
|
|
|
|
&& trace_end_match ()
|
|
|
|
&& ( (is_quandary_alloc_issue quandary_issue && is_inferbo_alloc_issue inferbo_issue)
|
|
|
|
|| (is_quandary_access_issue quandary_issue && is_inferbo_access_issue inferbo_issue) )
|
|
|
|
in
|
|
|
|
let paired_issues =
|
|
|
|
(* Can be computed more efficiently (in n*log(n)) by using a Map mapping
|
|
|
|
file name + line number to quandary_issues to match with inferbo_issues *)
|
|
|
|
List.concat_map quandary_issues ~f:(fun quandary_issue ->
|
|
|
|
List.filter_map inferBO_issues ~f:(fun inferbo_issue ->
|
|
|
|
if matching_issues quandary_issue inferbo_issue then
|
|
|
|
Some (quandary_issue, inferbo_issue)
|
|
|
|
else None ) )
|
|
|
|
in
|
|
|
|
let merge_issues (issue1, issue2) =
|
|
|
|
{ Issue.proc_name= issue1.Issue.proc_name
|
|
|
|
; proc_location= {issue1.Issue.proc_location with col= -1}
|
|
|
|
; err_key=
|
|
|
|
Errlog.merge_err_key issue1.Issue.err_key issue2.Issue.err_key
|
|
|
|
~merge_issues:(fun issue1 _ ->
|
|
|
|
if IssueType.equal issue1 IssueType.untrusted_buffer_access then
|
|
|
|
IssueType.tainted_buffer_access
|
|
|
|
else IssueType.tainted_memory_allocation )
|
|
|
|
~merge_descriptions:(fun descs1 descs2 ->
|
|
|
|
String.concat
|
|
|
|
( "QuandaryBO error. Quandary error(s): \""
|
|
|
|
:: (descs1 @ ("\". InferBO error(s):\"" :: (descs2 @ ["\"."]))) ) )
|
|
|
|
; err_data= Errlog.merge_err_data issue1.Issue.err_data issue2.Issue.err_data }
|
|
|
|
in
|
|
|
|
(* Can merge List.map, List.concat_map and List.filter_map into a single fold. *)
|
|
|
|
let quandaryBO_issues = List.map ~f:merge_issues paired_issues in
|
|
|
|
let quandary_issues =
|
|
|
|
IssueType.
|
|
|
|
[ quandary_taint_error
|
|
|
|
; shell_injection
|
|
|
|
; shell_injection_risk
|
|
|
|
; sql_injection
|
|
|
|
; sql_injection_risk
|
|
|
|
; untrusted_buffer_access
|
|
|
|
; untrusted_file_risk
|
|
|
|
; untrusted_heap_allocation
|
|
|
|
; untrusted_url_risk
|
|
|
|
; untrusted_variable_length_array
|
|
|
|
; user_controlled_sql_risk ]
|
|
|
|
in
|
|
|
|
let inferbo_issues =
|
|
|
|
inferbo_alloc_issues @ inferbo_access_issues @ [IssueType.unreachable_code_after]
|
|
|
|
in
|
|
|
|
let filtered_issues = Config.quandaryBO_filtered_issues in
|
|
|
|
let all_issues_filtered =
|
|
|
|
List.filter
|
|
|
|
~f:(fun issue ->
|
|
|
|
let issue_in ls = List.mem ls issue.Issue.err_key.err_name ~equal:IssueType.equal in
|
|
|
|
(Config.quandary || not (issue_in quandary_issues))
|
|
|
|
&& (Config.bufferoverrun || not (issue_in inferbo_issues))
|
|
|
|
&& not (issue_in filtered_issues) )
|
|
|
|
all_issues
|
|
|
|
in
|
|
|
|
List.rev_append all_issues_filtered quandaryBO_issues
|