Source file components.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
open Cil_types
open Cil_datatype
open Pdg_types
(** {2 Searching security annotations} *)
(** {2 Computing security components} *)
open PdgIndex
let get_node_stmt node = Key.stmt (Pdg.Api.node_key node)
module NodeKf = Datatype.Pair(PdgTypes.Node)(Kernel_function)
module Todolist : sig
type todo = private
{ node: PdgTypes.Node.t;
kf: kernel_function;
pdg: Pdg.Api.t;
callstack_length: int;
from_deep: bool }
type t = todo list
val mk_init: kernel_function -> Pdg.Api.t -> PdgTypes.Node.t list -> todo list
val add:
PdgTypes.Node.t -> kernel_function -> Pdg.Api.t -> int -> bool -> t -> t
end = struct
type todo =
{ node: PdgTypes.Node.t;
kf: kernel_function;
pdg: Pdg.Api.t;
callstack_length: int;
from_deep: bool }
type t = todo list
let add n kf pdg len fd list =
match Pdg.Api.node_key n with
| Key.SigKey (Signature.In Signature.InCtrl) ->
list
| Key.VarDecl vi when not (Kernel.LibEntry.get () && vi.vglob) ->
list
| _ ->
Security_slicing_parameters.debug ~level:2 "adding node %a (in %s)"
(Pdg.Api.pretty_node false) n
(Kernel_function.get_name kf);
{ node = n; kf = kf; pdg = pdg;
callstack_length = len; from_deep = fd }
:: list
let mk_init kf pdg =
List.fold_left (fun acc n -> add n kf pdg 0 false acc) []
end
module Component = struct
module M = Map.Make(NodeKf)
type fwd_kind = Impact | Security
type kind =
| Direct
| Indirect_Backward
| Forward of fwd_kind
type value =
{ pdg: Pdg.Api.t;
mutable callstack_length: int;
mutable direct: bool;
mutable indirect_backward: bool;
mutable forward: bool }
type t = value M.t
let is_direct v = v.direct
let is_indirect_backward v = v.indirect_backward && not v.direct
let is_forward v = not (v.direct || v.indirect_backward)
(** Returns [found, new_already] with:
- [found] is [true] iff [elt] was previously added for [kind]
- [new_already] is [already] updated with [elt] and its (new) associated
value. *)
let check_and_add first elt kind pdg len (already: t) =
try
let v = M.find elt already in
let found, dir, up, down = match kind with
| Direct -> true, true, false, false
| Indirect_Backward -> v.indirect_backward, v.direct, true, false
| Forward _ -> v.forward, v.direct, v.indirect_backward, true
in
v.callstack_length <- min v.callstack_length len;
v.direct <- dir;
v.indirect_backward <- up;
v.forward <- down;
found, already
with Not_found ->
let dir, up, down = match kind with
| Direct -> true, false, false
| Indirect_Backward -> false, true, false
| Forward _ -> false, false, true
in
let v =
{ pdg = pdg; callstack_length = len;
direct = dir; indirect_backward = up; forward = down }
in
false,
if first && kind = Forward Impact then
already
else
M.add elt v already
let one_step_related_nodes kind pdg node =
let direct node = Pdg.Api.direct_data_dpds pdg node in
match kind with
| Direct -> direct node
| Indirect_Backward -> direct node @ Pdg.Api.direct_ctrl_dpds pdg node
| Forward Security ->
Pdg.Api.direct_data_uses pdg node @ Pdg.Api.direct_ctrl_uses pdg node
| Forward Impact ->
Pdg.Api.direct_data_uses pdg node @ Pdg.Api.direct_ctrl_uses pdg node
@ Pdg.Api.direct_addr_uses pdg node
let search_input kind kf lazy_l =
try
match kind with
| Forward _ -> Lazy.force lazy_l
| Direct | Indirect_Backward ->
if Eva.Analysis.use_spec_instead_of_definition kf
then Lazy.force lazy_l
else []
with Not_found ->
[]
let add_from_deep caller todo n =
Todolist.add n caller (Pdg.Api.get caller) 0 true todo
let forward_caller kf node todolist =
let pdg = Pdg.Api.get kf in
List.fold_left
(fun todolist (caller, callsites) ->
List.fold_left
(fun todolist callsite ->
let nodes =
Pdg.Api.find_call_out_nodes_to_select
pdg (PdgTypes.NodeSet.singleton node) (Pdg.Api.get caller) callsite
in
List.fold_left
(add_from_deep caller)
todolist
nodes)
todolist
callsites)
todolist
(Eva.Results.callsites kf)
let related_nodes_of_nodes kind result nodes =
let initial_nodes =
List.map (fun n -> n.Todolist.node, n.Todolist.kf) nodes
in
let rec aux first result = function
| [] -> result
| { Todolist.node = node; kf = kf; pdg = pdg;
callstack_length = callstack_length; from_deep = from_deep }
:: todolist
->
let elt = node, kf in
let found, result =
check_and_add first elt kind pdg callstack_length result
in
let todolist =
if found then begin
todolist
end else begin
Security_slicing_parameters.debug
~level:2 "considering node %a (in %s)"
(Pdg.Api.pretty_node false) node
(Kernel_function.get_name kf);
let related_nodes = one_step_related_nodes kind pdg node in
Security_slicing_parameters.debug ~level:3
"intraprocedural part done";
let todolist =
List.fold_left
(fun todo n ->
Todolist.add n kf pdg callstack_length false todo)
todolist
related_nodes
in
let backward_from_deep compute_nodes =
match kind, callstack_length with
| (Direct | Indirect_Backward), 0 ->
let do_caller todolist (caller, callsites) =
let pdg_caller = Pdg.Api.get caller in
let do_call todolist callsite =
match kind with
| Direct | Indirect_Backward ->
let nodes = compute_nodes pdg_caller callsite in
List.fold_left
(add_from_deep caller) todolist nodes
| Forward _ ->
todolist
in
List.fold_left do_call todolist callsites
in
List.fold_left do_caller todolist (Eva.Results.callsites kf)
| _ ->
todolist
in
let todolist =
match Pdg.Api.node_key node with
| Key.SigKey (Signature.In Signature.InCtrl) ->
assert false
| Key.SigKey (Signature.In (Signature.InImpl zone)) ->
let compute_nodes pdg_caller callsite =
let nodes, _undef_zone =
Pdg.Api.find_location_nodes_at_stmt
pdg_caller callsite ~before:true zone
in
let nodes = List.map (fun (n, _z_part) -> n) nodes in
nodes
in
backward_from_deep compute_nodes
| Key.SigKey key ->
let compute_nodes pdg_caller callsite =
[ match key with
| Signature.In (Signature.InNum n) ->
Pdg.Api.find_call_input_node pdg_caller callsite n
| Signature.Out Signature.OutRet ->
Pdg.Api.find_call_output_node pdg_caller callsite
| Signature.In
(Signature.InCtrl | Signature.InImpl _)
| Signature.Out _ ->
assert false ]
in
backward_from_deep compute_nodes
| Key.SigCallKey(id, key) ->
if from_deep then
todolist
else
let stmt = Key.call_from_id id in
let called_kfs = Eva.Results.callee stmt in
let todolist =
List.fold_left
(fun todolist called_kf ->
let called_pdg = Pdg.Api.get called_kf in
let nodes =
try
match kind, key with
| (Direct | Indirect_Backward),
Signature.Out out_key ->
let nodes, _undef_zone =
Pdg.Api.find_output_nodes called_pdg out_key
in
let nodes =
List.map (fun (n, _z_part) -> n) nodes in
nodes
| _, Signature.In (Signature.InNum n) ->
search_input kind called_kf
(lazy [Pdg.Api.find_input_node called_pdg n])
| _, Signature.In Signature.InCtrl ->
search_input kind called_kf
(lazy
[Pdg.Api.find_entry_point_node called_pdg])
| _, Signature.In (Signature.InImpl _) ->
assert false
| Forward _, Signature.Out _ ->
[]
with
| Pdg.Api.Top ->
Security_slicing_parameters.warning
"no precise pdg for function %s. \n\
Ignoring this function in the analysis (potentially incorrect results)."
(Kernel_function.get_name called_kf);
[]
| Pdg.Api.Bottom | Not_found -> assert false
in
List.fold_left
(fun todo n ->
Todolist.add
n called_kf called_pdg
(callstack_length + 1) false todo)
todolist
nodes)
todolist
called_kfs
in
(match kind with
| Direct | Indirect_Backward ->
todolist
| Forward _ ->
List.fold_left
(fun todolist called_kf ->
let compute_from_stmt fold =
fold
(fun (n, kfn) _ acc ->
if Kernel_function.equal kfn kf then n :: acc
else acc)
in
let from_stmt =
compute_from_stmt M.fold result [] in
let from_stmt =
compute_from_stmt
(fun f e acc ->
List.fold_left
(fun acc e -> f e [] acc) acc e)
initial_nodes
from_stmt
in
let from_stmt = List.fold_left
(fun s n -> PdgTypes.NodeSet.add n s)
PdgTypes.NodeSet.empty from_stmt in
let called_pdg = Pdg.Api.get called_kf in
let nodes =
try
Pdg.Api.find_in_nodes_to_select_for_this_call
pdg from_stmt stmt called_pdg
with
| Pdg.Api.Top ->
[]
| Pdg.Api.Bottom | Not_found -> assert false
in
List.fold_left
(fun todo n ->
Todolist.add
n called_kf called_pdg
(callstack_length + 1) false todo)
todolist
nodes)
todolist
called_kfs)
| Key.CallStmt _ | Key.VarDecl _ ->
assert false
| Key.Stmt _ | Key.Label _ ->
todolist
in
match kind with
| (Direct | Indirect_Backward) -> todolist
| Forward _ -> forward_caller kf node todolist
end
in
aux false result todolist
in
aux true result nodes
let initial_nodes kf stmt =
Security_slicing_parameters.debug
~level:3 "computing initial nodes for %d" stmt.sid;
let pdg = Pdg.Api.get kf in
let nodes =
if Eva.Results.is_reachable stmt then
try Pdg.Api.find_simple_stmt_nodes pdg stmt
with Not_found -> assert false
else begin
Security_slicing_parameters.debug
~level:3 "stmt %d is dead. skipping." stmt.sid;
[]
end
in
Todolist.mk_init kf pdg nodes
let direct kf stmt =
try
let nodes = initial_nodes kf stmt in
Security_slicing_parameters.debug
"computing direct component %d" stmt.sid;
let res = related_nodes_of_nodes Direct M.empty nodes in
let mk p =
{ pdg = p; callstack_length = 0;
direct = true; indirect_backward = false; forward = false }
in
let res =
List.fold_left
(fun acc { Todolist.node=n; kf=f; pdg=p } -> M.add (n,f) (mk p) acc)
res
nodes
in
res
with Pdg.Api.Top | Pdg.Api.Bottom ->
Security_slicing_parameters.warning "PDG is not manageable. skipping.";
M.empty
let backward kf stmt =
try
let nodes = initial_nodes kf stmt in
let res = direct kf stmt in
Security_slicing_parameters.debug
"computing backward indirect component for %d" stmt.sid;
related_nodes_of_nodes Indirect_Backward res nodes
with Pdg.Api.Top | Pdg.Api.Bottom ->
Security_slicing_parameters.warning "PDG is not manageable. skipping.";
M.empty
let whole kf stmt =
let res = backward kf stmt in
let from =
M.fold
(fun (n,kf) v acc ->
Todolist.add n kf v.pdg v.callstack_length false acc)
res
[]
in
Security_slicing_parameters.debug
"computing forward component for stmt %d" stmt.sid;
related_nodes_of_nodes (Forward Security) res from
let forward fwd_kind kf stmt =
let nodes = initial_nodes kf stmt in
Security_slicing_parameters.debug
"computing forward component for stmt %d" stmt.sid;
let res = related_nodes_of_nodes (Forward fwd_kind) M.empty nodes in
let set =
M.fold
(fun (n,_) _ acc ->
Option.fold
~none:acc
~some:(fun s -> Stmt.Set.add s acc)
(get_node_stmt n))
res
Stmt.Set.empty
in
Stmt.Set.elements set
let get_component kind stmt =
let kf = Kernel_function.find_englobing_kf stmt in
let action, check = match kind with
| Direct -> direct, is_direct
| Indirect_Backward -> backward, is_indirect_backward
| Forward _ -> whole, is_forward
in
let set =
M.fold
(fun (n,_) v acc ->
if check v then
Option.fold
~none:acc
~some:(fun s -> Stmt.Set.add s acc)
(get_node_stmt n)
else
acc)
(action kf stmt)
Stmt.Set.empty
in
Stmt.Set.elements set
end
let register name arg =
Dynamic.register
~plugin:"Security_slicing"
name
(Datatype.func Stmt.ty (Datatype.list Stmt.ty))
(Component.get_component arg)
let get_direct_component = register "get_direct_component" Component.Direct
let get_indirect_backward_component =
register "get_indirect_backward_component" Component.Indirect_Backward
let get_forward_component = register "get_forward_component"
(Component.Forward Component.Security)
let impact_analysis =
Dynamic.register
~plugin:"Security_slicing"
"impact_analysis"
(Datatype.func2 Kernel_function.ty Stmt.ty (Datatype.list Stmt.ty))
(Component.forward Component.Impact)