Skip to content

Commit 3fc209f

Browse files
Merge pull request #952 from FelixKrayer/taint
Taint analysis to improve the precision loss of partial contexts
2 parents 5e5be57 + b663598 commit 3fc209f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+678
-77
lines changed

src/analyses/abortUnless.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ struct
4646
in
4747
[false, candidate]
4848

49-
let combine ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (au:D.t) : D.t =
49+
let combine ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (au:D.t) (f_ask: Queries.ask) : D.t =
5050
if au && lval = None then (
5151
(* Assert happens after evaluation of call, so if variables in `arg` are assigned to, asserting might unsoundly yield bot *)
5252
(* See test 62/03 *)

src/analyses/accessAnalysis.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ struct
9898
let enter ctx lv f args : (D.t * D.t) list =
9999
[(ctx.local,ctx.local)]
100100

101-
let combine ctx lv fexp f args fc al =
101+
let combine ctx lv fexp f args fc al f_ask =
102102
access_one_top ctx Read false fexp;
103103
begin match lv with
104104
| None -> ()

src/analyses/apron/relationAnalysis.apron.ml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ struct
350350
st'
351351
end
352352

353-
let combine ctx r fe f args fc fun_st =
353+
let combine ctx r fe f args fc fun_st (f_ask : Queries.ask) =
354354
let st = ctx.local in
355355
let reachable_from_args = List.fold (fun ls e -> Queries.LS.join ls (ctx.ask (ReachableFrom e))) (Queries.LS.empty ()) args in
356356
let fundec = Node.find_fundec ctx.node in
@@ -378,10 +378,14 @@ struct
378378
let arg_vars = f.sformals |> List.filter (RD.Tracked.varinfo_tracked) |> List.map RV.arg in
379379
if M.tracing then M.tracel "combine" "relation remove vars: %a\n" (docList (fun v -> Pretty.text (RD.Var.to_string v))) arg_vars;
380380
RD.remove_vars_with new_fun_rel arg_vars; (* fine to remove arg vars that also exist in caller because unify from new_rel adds them back with proper constraints *)
381+
let tainted = f_ask.f Queries.MayBeTainted in
382+
let tainted_vars = TaintPartialContexts.conv_varset tainted in
381383
let new_rel = RD.keep_filter st.rel (fun var ->
382384
match RV.find_metadata var with
383385
| Some (Local _) when not (pass_to_callee fundec any_local_reachable var) -> true (* keep caller locals, provided they were not passed to the function *)
384386
| Some (Arg _) -> true (* keep caller args *)
387+
| Some ((Local _ | Global _)) when not (RD.mem_var new_fun_rel var) -> false (* remove locals and globals, for which no record exists in the new_fun_apr *)
388+
| Some ((Local v | Global v)) when not (TaintPartialContexts.VS.mem v tainted_vars) -> true (* keep locals and globals, which have not been touched by the call *)
385389
| _ -> false (* remove everything else (globals, global privs, reachable things from the caller) *)
386390
)
387391
in

src/analyses/assert.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ struct
2727
let enter ctx (lval: lval option) (fd:fundec) (args:exp list) : (D.t * D.t) list =
2828
[ctx.local, ctx.local]
2929

30-
let combine ctx (lval:lval option) fexp (fd:fundec) (args:exp list) fc (au:D.t) : D.t =
30+
let combine ctx (lval:lval option) fexp (fd:fundec) (args:exp list) fc (au:D.t) (f_ask: Queries.ask) : D.t =
3131
au
3232

3333
let assert_fn ctx e check refine =

src/analyses/base.ml

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2247,7 +2247,36 @@ struct
22472247
in
22482248
if get_bool "sem.noreturn.dead_code" && Cil.hasAttribute "noreturn" f.vattr then raise Deadcode else st
22492249

2250-
let combine ctx (lval: lval option) fexp (f: fundec) (args: exp list) fc (after: D.t) : D.t =
2250+
let combine_st ctx (local_st : store) (fun_st : store) (tainted_lvs : Q.LS.t) : store =
2251+
let ask = (Analyses.ask_of_ctx ctx) in
2252+
Q.LS.fold (fun (v, o) st ->
2253+
if CPA.mem v fun_st.cpa then
2254+
let lval = Lval.CilLval.to_lval (v,o) in
2255+
let address = eval_lv ask ctx.global st lval in
2256+
let lval_type = (AD.get_type address) in
2257+
if M.tracing then M.trace "taintPC" "updating %a; type: %a\n" Lval.CilLval.pretty (v, o) d_type lval_type;
2258+
match (CPA.find_opt v (fun_st.cpa)), lval_type with
2259+
| None, _ -> st
2260+
(* partitioned arrays cannot be copied by individual lvalues, so if tainted just copy the whole callee value for the array variable *)
2261+
| Some (`Array a), _ when (CArrays.domain_of_t a) = PartitionedDomain -> {st with cpa = CPA.add v (`Array a) st.cpa}
2262+
(* "get" returned "unknown" when applied to a void type, so special case void types. This caused problems with some sv-comps (e.g. regtest 64 11) *)
2263+
| Some voidVal, TVoid _ -> {st with cpa = CPA.add v voidVal st.cpa}
2264+
| _, _ -> begin
2265+
let new_val = get ask ctx.global fun_st address None in
2266+
if M.tracing then M.trace "taintPC" "update val: %a\n\n" VD.pretty new_val;
2267+
let st' = set_savetop ~ctx ask ctx.global st address lval_type new_val in
2268+
let partDep = Dep.find_opt v fun_st.deps in
2269+
match partDep with
2270+
| None -> st'
2271+
(* if a var partitions an array, all cpa-info for arrays it may partition are added from callee to caller *)
2272+
| Some deps -> {st' with cpa = (Dep.VarSet.fold (fun v accCPA -> let val_opt = CPA.find_opt v fun_st.cpa in
2273+
match val_opt with
2274+
| None -> accCPA
2275+
| Some new_val -> CPA.add v new_val accCPA ) deps st'.cpa)}
2276+
end
2277+
else st) tainted_lvs local_st
2278+
2279+
let combine ctx (lval: lval option) fexp (f: fundec) (args: exp list) fc (after: D.t) (f_ask: Q.ask) : D.t =
22512280
let combine_one (st: D.t) (fun_st: D.t) =
22522281
if M.tracing then M.tracel "combine" "%a\n%a\n" CPA.pretty st.cpa CPA.pretty fun_st.cpa;
22532282
(* This function does miscellaneous things, but the main task was to give the
@@ -2258,9 +2287,27 @@ struct
22582287
let add_globals (st: store) (fun_st: store) =
22592288
(* Remove the return value as this is dealt with separately. *)
22602289
let cpa_noreturn = CPA.remove (return_varinfo ()) fun_st.cpa in
2261-
let cpa_local = CPA.filter (fun x _ -> not (is_global (Analyses.ask_of_ctx ctx) x)) st.cpa in
2262-
let cpa' = CPA.fold CPA.add cpa_noreturn cpa_local in (* add cpa_noreturn to cpa_local *)
2263-
{ fun_st with cpa = cpa' }
2290+
let ask = (Analyses.ask_of_ctx ctx) in
2291+
let tainted = f_ask.f Q.MayBeTainted in
2292+
if M.tracing then M.trace "taintPC" "combine for %s in base: tainted: %a\n" f.svar.vname Q.LS.pretty tainted;
2293+
if M.tracing then M.trace "taintPC" "combine base:\ncaller: %a\ncallee: %a\n" CPA.pretty st.cpa CPA.pretty fun_st.cpa;
2294+
begin if (Q.LS.is_top tainted) then
2295+
let cpa_local = CPA.filter (fun x _ -> not (is_global ask x)) st.cpa in
2296+
let cpa' = CPA.fold CPA.add cpa_noreturn cpa_local in (* add cpa_noreturn to cpa_local *)
2297+
if M.tracing then M.trace "taintPC" "combined: %a\n" CPA.pretty cpa';
2298+
{ fun_st with cpa = cpa' }
2299+
else
2300+
(* remove variables from caller cpa, that are global and not in the callee cpa *)
2301+
let cpa_caller = CPA.filter (fun x _ -> (not (is_global ask x)) || CPA.mem x fun_st.cpa) st.cpa in
2302+
(* add variables from callee that are not in caller yet *)
2303+
let cpa_new = CPA.filter (fun x _ -> not (CPA.mem x cpa_caller)) cpa_noreturn in
2304+
let cpa_caller' = CPA.fold CPA.add cpa_new cpa_caller in
2305+
(* remove lvals from the tainted set that correspond to variables for which we just added a new mapping from the callee*)
2306+
let tainted = Q.LS.filter (fun (v, _) -> not (CPA.mem v cpa_new)) tainted in
2307+
let st_combined = combine_st ctx {st with cpa = cpa_caller'} fun_st tainted in
2308+
if M.tracing then M.trace "taintPC" "combined: %a\n" CPA.pretty st_combined.cpa;
2309+
{ fun_st with cpa = st_combined.cpa }
2310+
end
22642311
in
22652312
let return_var = return_var () in
22662313
let return_val =
@@ -2271,7 +2318,7 @@ struct
22712318
let nst = add_globals st fun_st in
22722319

22732320
(* Projection to Precision of the Caller *)
2274-
let p = PrecisionUtil.int_precision_from_node ()in (* Since f is the fundec of the Callee we have to get the fundec of the current Node instead *)
2321+
let p = PrecisionUtil.int_precision_from_node () in (* Since f is the fundec of the Callee we have to get the fundec of the current Node instead *)
22752322
let callerFundec = match !MyCFG.current_node with
22762323
| Some n -> Node.find_fundec n
22772324
| None -> failwith "callerfundec not found"

src/analyses/condVars.ml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ module Domain = struct
3636
let only_locals d =
3737
let p v = not v.vglob in
3838
filter_vars p d
39+
let only_untainted d tainted =
40+
let p v = (not v.vglob) || not (TaintPartialContexts.VS.mem v tainted) in
41+
filter_vars p d
3942
let only_global_exprs s = V.for_all (var_in_expr (fun v -> v.vglob)) s
4043
let rec get k d =
4144
if mem k d && V.cardinal (find k d) = 1 then
@@ -104,7 +107,7 @@ struct
104107
let save_expr lval expr =
105108
match mustPointTo ctx (AddrOf lval) with
106109
| Some clval ->
107-
if M.tracing then M.tracel "condvars" "CondVars: saving %a = %a" Lval.CilLval.pretty clval d_exp expr;
110+
if M.tracing then M.tracel "condvars" "CondVars: saving %a = %a\n" Lval.CilLval.pretty clval d_exp expr;
108111
D.add clval (D.V.singleton expr) d (* if lval must point to clval, add expr *)
109112
| None -> d
110113
in
@@ -136,13 +139,15 @@ struct
136139
let enter ctx (lval: lval option) (f:fundec) (args:exp list) : (D.t * D.t) list =
137140
[ctx.local, D.bot ()]
138141

139-
let combine ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (au:D.t) : D.t =
142+
let combine ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (au:D.t) (f_ask: Queries.ask) : D.t =
140143
(* combine caller's state with globals from callee *)
141144
(* TODO (precision): globals with only global vars are kept, the rest is lost -> collect which globals are assigned to *)
142145
(* D.merge (fun k s1 s2 -> match s2 with Some ss2 when (fst k).vglob && D.only_global_exprs ss2 -> s2 | _ when (fst k).vglob -> None | _ -> s1) ctx.local au *)
143-
D.only_locals ctx.local (* globals might have changed... *)
146+
let tainted = TaintPartialContexts.conv_varset (f_ask.f Queries.MayBeTainted) in
147+
D.only_untainted ctx.local tainted (* tainted globals might have changed... *)
144148

145149
let special ctx (lval: lval option) (f:varinfo) (arglist:exp list) : D.t =
150+
(* TODO: shouldn't there be some kind of invalidadte, depending on the effect of the special function? *)
146151
ctx.local
147152

148153
let startstate v = D.bot ()

src/analyses/expRelation.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ struct
9999
let enter ctx (lval: lval option) (f:fundec) (args:exp list) : (D.t * D.t) list =
100100
[ctx.local, ctx.local]
101101

102-
let combine ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (au:D.t) : D.t =
102+
let combine ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (au:D.t) (f_ask: Queries.ask) : D.t =
103103
au
104104

105105
let special ctx (lval: lval option) (f:varinfo) (arglist:exp list) : D.t =

src/analyses/expsplit.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ struct
4646
let return ctx (exp:exp option) (f:fundec) =
4747
emit_splits_ctx ctx
4848

49-
let combine ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc au =
49+
let combine ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc au (f_ask: Queries.ask) =
5050
let d = D.join ctx.local au in
5151
emit_splits ctx d
5252

src/analyses/extractPthread.ml

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,14 +1057,7 @@ module Spec : Analyses.MCPSpec = struct
10571057
[ (d_caller, d_callee) ]
10581058

10591059

1060-
let combine
1061-
ctx
1062-
(lval : lval option)
1063-
fexp
1064-
(f : fundec)
1065-
(args : exp list)
1066-
fc
1067-
(au : D.t) : D.t =
1060+
let combine ctx (lval : lval option) fexp (f : fundec) (args : exp list) fc (au : D.t) (f_ask: Queries.ask) : D.t =
10681061
if D.any_is_bot ctx.local || D.any_is_bot au
10691062
then ctx.local
10701063
else

src/analyses/fileUse.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ struct
163163
D.extend_value unclosed_var (mustOpen, mayOpen) m
164164
) else m
165165

166-
let combine ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (au:D.t) : D.t =
166+
let combine ctx (lval:lval option) fexp (f:fundec) (args:exp list) fc (au:D.t) (f_ask: Queries.ask) : D.t =
167167
let m = ctx.local in
168168
(* pop the last location off the stack *)
169169
let m = D.edit_callstack List.tl m in (* TODO could it be problematic to keep this in the caller instead of callee domain? if we only add the stack for the callee in enter, then there would be no need to pop a location anymore... *)

0 commit comments

Comments
 (0)