diff --git a/infer/src/base/IssueType.ml b/infer/src/base/IssueType.ml index e569df9a7..6684f5993 100644 --- a/infer/src/base/IssueType.ml +++ b/infer/src/base/IssueType.ml @@ -329,6 +329,8 @@ let unsafe_guarded_by_access = from_string "UNSAFE_GUARDED_BY_ACCESS" let use_after_free = from_string "USE_AFTER_FREE" +let user_controlled_sql_risk = from_string "USER_CONTROLLED_SQL_RISK" + let untrusted_deserialization = from_string "UNTRUSTED_DESERIALIZATION" let untrusted_file = from_string "UNTRUSTED_FILE" @@ -337,8 +339,10 @@ let untrusted_file_risk = from_string "UNTRUSTED_FILE_RISK" let untrusted_intent_creation = from_string "UNTRUSTED_INTENT_CREATION" -let untrusted_variable_length_array = from_string "UNTRUSTED_VARIABLE_LENGTH_ARRAY" +let untrusted_url = from_string "UNTRUSTED_URL" -let user_controlled_sql_risk = from_string "USER_CONTROLLED_SQL_RISK" +let untrusted_url_risk = from_string "UNTRUSTED_URL_RISK" + +let untrusted_variable_length_array = from_string "UNTRUSTED_VARIABLE_LENGTH_ARRAY" let wrong_argument_number = from_string "Wrong_argument_number" ~hum:"Wrong Argument Number" diff --git a/infer/src/base/IssueType.mli b/infer/src/base/IssueType.mli index 56c6e6bde..de4dccc8b 100644 --- a/infer/src/base/IssueType.mli +++ b/infer/src/base/IssueType.mli @@ -238,8 +238,6 @@ val unsafe_guarded_by_access : t val use_after_free : t -val user_controlled_sql_risk : t - val untrusted_deserialization : t val untrusted_file : t @@ -248,6 +246,12 @@ val untrusted_file_risk : t val untrusted_intent_creation : t +val untrusted_url : t + +val untrusted_url_risk : t + val untrusted_variable_length_array : t +val user_controlled_sql_risk : t + val wrong_argument_number : t diff --git a/infer/src/quandary/ClangTrace.ml b/infer/src/quandary/ClangTrace.ml index e44807c1f..24cc840f7 100644 --- a/infer/src/quandary/ClangTrace.ml +++ b/infer/src/quandary/ClangTrace.ml @@ -177,6 +177,7 @@ module SinkKind = struct | BufferAccess (** read/write an array *) | CreateFile (** create/open a file *) | HeapAllocation (** heap memory allocation *) + | Network (** network access *) | ShellExec (** shell exec function *) | SQL (** SQL query *) | StackAllocation (** stack memory allocation *) @@ -192,6 +193,8 @@ module SinkKind = struct CreateFile | "HeapAllocation" -> HeapAllocation + | "Network" -> + Network | "ShellExec" -> ShellExec | "SQL" -> @@ -214,6 +217,17 @@ module SinkKind = struct if n < List.length actuals then Some (kind, IntSet.singleton n) else None + (* taint all parameters after the nth (exclusive) *) + let taint_after_nth n kind actuals = + match + List.filter_mapi ~f:(fun actual_num _ -> Option.some_if (actual_num > n) actual_num) actuals + with + | [] -> + None + | to_taint -> + Some (kind, IntSet.of_list to_taint) + + let taint_all kind actuals = Some (kind, IntSet.of_list (List.mapi ~f:(fun actual_num _ -> actual_num) actuals)) @@ -272,6 +286,9 @@ module SinkKind = struct match Typ.Procname.to_string pname with | "creat" | "fopen" | "freopen" | "open" -> taint_nth 0 CreateFile actuals + | "curl_easy_setopt" -> + (* first two actuals are curl object + a constant *) + taint_after_nth 1 Network actuals | "execl" | "execlp" | "execle" | "execv" | "execve" | "execvp" | "system" -> taint_all ShellExec actuals | "openat" -> @@ -311,6 +328,8 @@ module SinkKind = struct "CreateFile" | HeapAllocation -> "HeapAllocation" + | Network -> + "Network" | ShellExec -> "ShellExec" | SQL -> @@ -380,6 +399,12 @@ include Trace.Make (struct Option.some_if (is_injection_possible ~typ sanitizers) IssueType.untrusted_file | Endpoint (_, typ), CreateFile -> Option.some_if (is_injection_possible ~typ sanitizers) IssueType.untrusted_file_risk + | UserControlledEndpoint (_, typ), Network -> + Option.some_if (is_injection_possible ~typ sanitizers) IssueType.untrusted_url + | Endpoint (_, typ), Network -> + Option.some_if (is_injection_possible ~typ sanitizers) IssueType.untrusted_url_risk + | (CommandLineFlag _ | EnvironmentVariable | ReadFile), Network -> + None | UserControlledEndpoint (_, typ), SQL -> if is_injection_possible ~typ sanitizers then Some IssueType.sql_injection else diff --git a/infer/tests/codetoanalyze/cpp/quandary/endpoints.cpp b/infer/tests/codetoanalyze/cpp/quandary/endpoints.cpp index a851954da..45f142949 100644 --- a/infer/tests/codetoanalyze/cpp/quandary/endpoints.cpp +++ b/infer/tests/codetoanalyze/cpp/quandary/endpoints.cpp @@ -15,6 +15,8 @@ extern void __infer_sql_sink(std::string); extern std::string __infer_all_sanitizer(std::string); extern std::string __infer_string_sanitizer(std::string); +extern void curl_easy_setopt(void*, int, ...); + namespace facebook { namespace fb303 { namespace cpp2 { @@ -102,6 +104,12 @@ class Service1 : facebook::fb303::cpp2::FacebookServiceSvIf { file2.open(filename); } + const int CURLOPT_URL = 10002; + + void endpoint_to_curl_url_bad(request formal) { + curl_easy_setopt(nullptr, CURLOPT_URL, formal.s.c_str()); + } + void FP_service1_endpoint_struct_int_field_ok(request formal) { system(std::to_string(formal.i).c_str()); } diff --git a/infer/tests/codetoanalyze/cpp/quandary/issues.exp b/infer/tests/codetoanalyze/cpp/quandary/issues.exp index 35a49b09c..d16794156 100644 --- a/infer/tests/codetoanalyze/cpp/quandary/issues.exp +++ b/infer/tests/codetoanalyze/cpp/quandary/issues.exp @@ -37,6 +37,7 @@ codetoanalyze/cpp/quandary/basics.cpp, basics::via_field_bad2, 2, QUANDARY_TAINT codetoanalyze/cpp/quandary/basics.cpp, basics::via_passthrough_bad1, 4, QUANDARY_TAINT_ERROR, [Return from basics::Obj_string_source,Call to basics::Obj_string_sink] codetoanalyze/cpp/quandary/basics.cpp, basics::via_passthrough_bad2, 3, QUANDARY_TAINT_ERROR, [Return from basics::Obj_string_source,Call to basics::Obj_string_sink] codetoanalyze/cpp/quandary/endpoints.cpp, endpoints::Service1_FP_service1_endpoint_struct_int_field_ok, 1, REMOTE_CODE_EXECUTION_RISK, [Return from endpoints::Service1_FP_service1_endpoint_struct_int_field_ok,Call to system] +codetoanalyze/cpp/quandary/endpoints.cpp, endpoints::Service1_endpoint_to_curl_url_bad, 1, UNTRUSTED_URL_RISK, [Return from endpoints::Service1_endpoint_to_curl_url_bad,Call to curl_easy_setopt] codetoanalyze/cpp/quandary/endpoints.cpp, endpoints::Service1_fstream_open_file_bad, 1, UNTRUSTED_FILE_RISK, [Return from endpoints::Service1_fstream_open_file_bad,Call to std::basic_fstream>_basic_fstream] codetoanalyze/cpp/quandary/endpoints.cpp, endpoints::Service1_fstream_open_file_bad, 3, UNTRUSTED_FILE_RISK, [Return from endpoints::Service1_fstream_open_file_bad,Call to std::basic_fstream>_open] codetoanalyze/cpp/quandary/endpoints.cpp, endpoints::Service1_ifstream_open_file_bad, 1, UNTRUSTED_FILE_RISK, [Return from endpoints::Service1_ifstream_open_file_bad,Call to std::basic_ifstream>_basic_ifstream]