[quandary] treat call to unknown operator= as assignment

Summary: This lets us handle basic stuff like writes to fields.

Reviewed By: jvillard

Differential Revision: D5017735

fbshipit-source-id: 5697b12
master
Sam Blackshear 8 years ago committed by Facebook Github Bot
parent 9dc7e3d66f
commit a0377fe8c9

@ -265,6 +265,13 @@ module Make (TaintSpecification : TaintSpec.S) = struct
let exec_instr let exec_instr
(astate : Domain.astate) (proc_data : FormalMap.t ProcData.t) _ (instr : HilInstr.t) = (astate : Domain.astate) (proc_data : FormalMap.t ProcData.t) _ (instr : HilInstr.t) =
let exec_write lhs_access_path rhs_exp astate=
let rhs_node =
Option.value
(hil_exp_get_node rhs_exp astate proc_data)
~default:TaintDomain.empty_node in
TaintDomain.add_node (AccessPath.Exact lhs_access_path) rhs_node astate in
match instr with match instr with
| Write (((Var.ProgramVar pvar, _), []), HilExp.Exception _, _) when Pvar.is_return pvar -> | Write (((Var.ProgramVar pvar, _), []), HilExp.Exception _, _) when Pvar.is_return pvar ->
(* the Java frontend translates `throw Exception` as `return Exception`, which is a bit (* the Java frontend translates `throw Exception` as `return Exception`, which is a bit
@ -281,11 +288,7 @@ module Make (TaintSpecification : TaintSpec.S) = struct
astate astate
| Write (lhs_access_path, rhs_exp, _) -> | Write (lhs_access_path, rhs_exp, _) ->
let rhs_node = exec_write lhs_access_path rhs_exp astate
Option.value
(hil_exp_get_node rhs_exp astate proc_data)
~default:TaintDomain.empty_node in
TaintDomain.add_node (AccessPath.Exact lhs_access_path) rhs_node astate
| Call (ret_opt, Direct called_pname, actuals, call_flags, callee_loc) -> | Call (ret_opt, Direct called_pname, actuals, call_flags, callee_loc) ->
let handle_unknown_call callee_pname access_tree = let handle_unknown_call callee_pname access_tree =
@ -336,13 +339,24 @@ module Make (TaintSpecification : TaintSpec.S) = struct
| _ -> | _ ->
astate_acc in astate_acc in
let propagations = match Typ.Procname.get_method callee_pname with
TaintSpecification.handle_unknown_call | "operator=" when Typ.Procname.is_c_method callee_pname ->
callee_pname (* treat unknown calls to C++ operator= as assignment *)
(Option.map ~f:snd ret_opt) begin
actuals match actuals with
proc_data.tenv in | [AccessPath lhs_access_path; rhs_exp] ->
List.fold ~f:handle_unknown_call_ ~init:access_tree propagations in exec_write lhs_access_path rhs_exp access_tree
| _ ->
failwithf "Unexpected call to operator= %a" HilInstr.pp instr
end
| _ ->
let propagations =
TaintSpecification.handle_unknown_call
callee_pname
(Option.map ~f:snd ret_opt)
actuals
proc_data.tenv in
List.fold ~f:handle_unknown_call_ ~init:access_tree propagations in
let analyze_call astate_acc callee_pname = let analyze_call astate_acc callee_pname =
let call_site = CallSite.make callee_pname callee_loc in let call_site = CallSite.make callee_pname callee_loc in

@ -37,6 +37,11 @@
"kind": "Other", "kind": "Other",
"index": "0" "index": "0"
}, },
{
"procedure": "basics::template_sink",
"kind": "Other",
"index": "0"
},
{ {
"procedure": "basics::Obj::string_sink", "procedure": "basics::Obj::string_sink",
"kind": "Other", "kind": "Other",

@ -22,6 +22,8 @@ class Obj {
static void static_sink(void*) {} static void static_sink(void*) {}
std::string string_source(int i) { return ""; } std::string string_source(int i) { return ""; }
void string_sink(std::string) {} void string_sink(std::string) {}
std::string field1;
std::string field2;
}; };
void* returnSource() { return __infer_taint_source(); } void* returnSource() { return __infer_taint_source(); }
@ -68,6 +70,9 @@ T* template_source() {
return nullptr; return nullptr;
} }
template <class T>
void template_sink(T) {}
void template_source_bad() { void template_source_bad() {
void* source = template_source<void*>(); void* source = template_source<void*>();
__infer_taint_sink(source); __infer_taint_sink(source);
@ -77,4 +82,28 @@ void string_source_bad(Obj obj) {
std::string source = obj.string_source(5); std::string source = obj.string_source(5);
obj.string_sink(source); obj.string_sink(source);
} }
void via_field_bad1() {
Obj* obj = new Obj();
obj->field1 = *template_source<std::string>();
template_sink<std::string>(obj->field1);
}
void via_field_bad2(Obj* obj) {
obj->field1 = *template_source<std::string>();
template_sink<std::string>(obj->field1);
}
void via_field_ok1() {
Obj* obj = new Obj();
obj->field1 = *template_source<std::string>();
obj->field1 = nullptr;
template_sink<std::string>(obj->field1);
}
void via_field_ok2() {
Obj* obj = new Obj();
obj->field1 = *template_source<std::string>();
template_sink<std::string>(obj->field2);
}
} }

@ -6,6 +6,8 @@ codetoanalyze/cpp/quandary/basics.cpp, basics::sourceToSinkDirectBad, 2, QUANDAR
codetoanalyze/cpp/quandary/basics.cpp, basics::static_source_sink_bad, 2, QUANDARY_TAINT_ERROR, [return from basics::Obj_static_source,call to basics::Obj_static_sink] codetoanalyze/cpp/quandary/basics.cpp, basics::static_source_sink_bad, 2, QUANDARY_TAINT_ERROR, [return from basics::Obj_static_source,call to basics::Obj_static_sink]
codetoanalyze/cpp/quandary/basics.cpp, basics::string_source_bad, 2, QUANDARY_TAINT_ERROR, [return from basics::Obj_string_source,call to basics::Obj_string_sink] codetoanalyze/cpp/quandary/basics.cpp, basics::string_source_bad, 2, QUANDARY_TAINT_ERROR, [return from basics::Obj_string_source,call to basics::Obj_string_sink]
codetoanalyze/cpp/quandary/basics.cpp, basics::template_source_bad, 2, QUANDARY_TAINT_ERROR, [return from basics::template_source<void_*>,call to __infer_taint_sink] codetoanalyze/cpp/quandary/basics.cpp, basics::template_source_bad, 2, QUANDARY_TAINT_ERROR, [return from basics::template_source<void_*>,call to __infer_taint_sink]
codetoanalyze/cpp/quandary/basics.cpp, basics::via_field_bad1, 3, QUANDARY_TAINT_ERROR, [return from basics::template_source<std::basic_string<char>_>,call to basics::template_sink<std::basic_string<char>_>]
codetoanalyze/cpp/quandary/basics.cpp, basics::via_field_bad2, 2, QUANDARY_TAINT_ERROR, [return from basics::template_source<std::basic_string<char>_>,call to basics::template_sink<std::basic_string<char>_>]
codetoanalyze/cpp/quandary/execs.cpp, execs::callExecBad, 6, QUANDARY_TAINT_ERROR, [return from getenv,call to execl] codetoanalyze/cpp/quandary/execs.cpp, execs::callExecBad, 6, QUANDARY_TAINT_ERROR, [return from getenv,call to execl]
codetoanalyze/cpp/quandary/execs.cpp, execs::callExecBad, 8, QUANDARY_TAINT_ERROR, [return from getenv,call to execl] codetoanalyze/cpp/quandary/execs.cpp, execs::callExecBad, 8, QUANDARY_TAINT_ERROR, [return from getenv,call to execl]
codetoanalyze/cpp/quandary/execs.cpp, execs::callExecBad, 11, QUANDARY_TAINT_ERROR, [return from getenv,call to execl] codetoanalyze/cpp/quandary/execs.cpp, execs::callExecBad, 11, QUANDARY_TAINT_ERROR, [return from getenv,call to execl]

Loading…
Cancel
Save