1(*
2 * Copyright 2014, NICTA
3 *
4 * This software may be distributed and modified according to the terms of
5 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
6 * See "LICENSE_GPLv2.txt" for details.
7 *
8 * @TAG(NICTA_GPL)
9 *)
10
11(*********************************************************************************************************************)
12(*                                                                                                                   *)
13(*  This file contains the functions building the tool that translates AUTHORITY GRAPHS into INFOFLOW POLICY GRAPHS  *)
14(*                                                                                                                   *)
15(*********************************************************************************************************************)
16
17
18#open "stack";;
19
20(* We define type auth, describing the different authority labels *)
21
22type auth = Read|Write|Receive|ASyncSend|SyncSend|Control|Reset|ASIDPodMapsASID;;
23
24
25(*********************************************************************************************************************)
26
27
28(* We define a bunch of elementary functions *)
29
30
31(* is_in g x checks whether x is an element of the list g *)
32
33let rec is_in g x= match g with
34|[] -> false
35|a::l -> (a=x)||(is_in l x);;
36
37
38
39(* simp_list l deletes elements in l so that every element does appear only once in the end *)
40
41let rec simp_list l = match l with
42|[] -> []
43|a::list -> if (is_in list a) then (simp_list list) else a::(simp_list list);;
44
45
46
47(* map f l maps f to every element of the list l *)
48
49let rec map f = function
50|[] -> []
51|a::l -> (f a)::(map f l);;
52
53
54
55(* unite l, where l is a 'a list list, appends all the list in l to give back a single list *)
56
57let rec unite = function
58|[] -> []
59|a::l->a@(unite l);;
60
61
62
63(* fixpoint f x does a fixpoint computation on x *)
64(* Simplification is necessary on (f x) for the step. We do it on x to ensure termination *)
65
66let rec fixpoint f x =
67let a = simp_list x and b = simp_list (f x) in match (a=b) with
68|true -> a
69|false -> fixpoint f b;;
70
71
72
73(* is_in_list2 g x, where x = (u,e,l) is of type ('a,auth,'a list), checks if there is an element a in the third field of x such that the edge (u,e,a) is in g *)
74
75let rec is_in_list2 g x = match x with
76|(_,_,[])-> false
77|(i,j,a::l)-> is_in g (i,j,a) || is_in_list2 g (i,j,l);;
78
79
80
81(* is_in_such g f checks if there is an element x in g such that (f g) holds *)
82
83let rec is_in_such g f = match g with
84|[] -> false
85|(t::l) -> (is_in g t && f t)||is_in_such l f;;
86
87
88
89(* those_is_in_such2 g f grabs all the elements x in l such that (f x) holds *)
90
91let rec those_is_in_such2 g f = match g with
92  |[] -> []
93  |a::l -> if (is_in g a && f a) then a::(those_is_in_such2 l f) else (those_is_in_such2 l f);;
94
95
96
97(* inter_non_empty l1 l2 checks if there is an element both in l1 and l2 *)
98
99let rec inter_non_empty l1 l2 = match l1 with
100|[] -> false
101|(a::l) -> is_in l2 a || inter_non_empty l l2;;
102
103
104
105(* nodes g returns the list of all nodes in the graph g *)
106(* We simplify it so that every node only appears once *)
107
108let rec nodes g =
109  let rec nodes_aux g = match g with
110    |[] -> []
111    |(a,auth,b)::l->a::b::(nodes_aux l)
112  in simp_list (nodes_aux g);;
113
114
115(*********************************************************************************************************************)
116
117
118(* add_selfedges g adds the self-edges to autority graph g *)
119
120let rec add_selfedges g =
121  let rec add_selfedge l x = match l with
122    |[] -> []
123    |a::l -> (x,a,x)::(add_selfedge l x)
124  in let authorities = [Read;Write;Receive;ASyncSend;SyncSend;Control;Reset;ASIDPodMapsASID]
125  in unite (map (add_selfedge authorities) (nodes g));;
126
127
128(*********************************************************************************************************************)
129
130
131(* subjectReadsp g l x acc is the function that checks is x is in the "subjectReads g l" set, where acc is that set during the fixpoint computation *)
132(* NB : some rules are particular cases, only useful if the self-edges have been ommitted *)
133
134let subjectReadsp g l x acc =
135  (l=x)||
136  is_in g (l,Read,x)||
137  is_in g (l,Receive,x)||
138  is_in g (l,SyncSend,x)||
139  is_in_such acc (fun t -> is_in g (t, Read, x))||
140   (
141     is_in_such acc (fun t -> is_in g (t,SyncSend, x) || is_in g (t, Receive,x))
142       &&
143     is_in_such (nodes g) (fun a -> is_in g (a,ASyncSend,x) || is_in g (a,SyncSend,x) || is_in g (a,Reset,x))
144   )||
145  is_in_such acc (fun b -> is_in g (x,Write,b))||
146   (
147     let f = (fun ep -> is_in g (x,SyncSend,ep)) in
148     is_in_such acc f
149      &&
150     (let ep_list = those_is_in_such2 acc f in let h = (fun a -> (is_in_list2 g (a,Receive,ep_list) || is_in_list2 g (a,Reset,ep_list))) in
151     is_in_such (nodes g) h)
152   )||
153   (
154     let f = (fun ep -> is_in g (x,Receive,ep)) in
155     is_in_such acc f
156      &&
157     (let ep_list = those_is_in_such2 acc f in let h = (fun a -> is_in_list2 g (a,SyncSend,ep_list)) in
158     is_in_such (nodes g) h)
159   )||
160  is_in g (x,Receive,l)||is_in g (x,SyncSend,l)||is_in g (x,Write,l)
161;;
162
163
164
165(* subjectReads g l computes the list containing the elements of the set "subjectReads g l", via a fixpoint computation *)
166
167let subjectReads g l =
168  let subjectReadsq g l ac=
169    let rec subjectReads_aux g l node_list acc= match (node_list) with
170      |[] -> acc
171      |(x::list) -> if (subjectReadsp g l x acc) then x::(subjectReads_aux g l list (x::acc))
172                                                 else (subjectReads_aux g l list (acc))
173    in simp_list (subjectReads_aux g l (nodes g) ac)
174  in fixpoint (subjectReadsq g l) [];;
175
176
177
178(* subjectAffectsp g l x acc is the function that checks is x is in the "subjectAffects g l" set, where acc is that set during the fixpoint computation *)
179(* NB : some rules are particular cases, only useful if the self-edges have been ommitted *)
180
181let subjectAffectsp g l x =
182  (l=x)||
183  is_in g (l,Control,x)||
184  is_in g (l,Write,x)||
185  is_in g (l,Receive,x)||
186  is_in g (l,ASyncSend,x)||
187  is_in g (l,SyncSend,x)||
188  is_in g (l,Reset,x)||
189  is_in g (l,ASIDPodMapsASID,x)||
190  (
191    let f = (fun ep -> is_in g (l,SyncSend,ep)||is_in g (l,ASyncSend,ep) ) in
192    is_in_such (nodes g) f
193     &&
194    (
195      let ep_list = those_is_in_such2 (nodes g) f in let h = (fun lp -> is_in_list2 g (lp,Receive,ep_list) && is_in g (lp,Write,x))
196    in is_in_such (nodes g) h
197    )
198  )||
199  (
200    let f = (fun ep -> is_in g (l,Reset,ep) ) in
201    is_in_such (nodes g) f
202     &&
203    (
204      let ep_list = those_is_in_such2 (nodes g) f in let h = (fun lp -> (is_in_list2 g (lp,Receive,ep_list)||is_in_list2 g (lp,SyncSend,ep_list)) && is_in g (lp,Write,x))
205    in is_in_such (nodes g) h
206    )
207  )||
208  inter_non_empty
209     (those_is_in_such2 (nodes g) (fun ep -> is_in g (l,Receive,ep)) )
210     (those_is_in_such2 (nodes g) (fun ep -> is_in g (x,SyncSend,ep)) ) ||
211  inter_non_empty
212     (those_is_in_such2 (nodes g) (fun ep -> is_in g (l,SyncSend,ep)||is_in g (l,ASyncSend,ep)||is_in g (l,Reset,ep)) )
213     (those_is_in_such2 (nodes g) (fun ep -> is_in g (x,Receive,ep)) ) ||
214  is_in g (x,SyncSend,l)||
215  is_in g (x,Receive,l)||
216  inter_non_empty
217     (those_is_in_such2 (nodes g) (fun lp -> is_in g (lp,Receive,l)||is_in g (lp,SyncSend,l)) )
218     (those_is_in_such2 (nodes g) (fun lp -> is_in g (lp,Write,x)) );;
219
220
221
222(* subjectAffects g l computes the list containing the elements of the set "subjectAffects g l", via a fixpoint computation *)
223
224let subjectAffects g l =
225  let subjectAffectsq g l ac=
226    let rec subjectAffects_aux g l node_list acc= match (node_list) with
227      |[] -> []
228      |(x::list) -> if (subjectAffectsp g l x) then x::(subjectAffects_aux g l list (x::acc))
229                                                 else (subjectAffects_aux g l list acc)
230    in simp_list (subjectAffects_aux g l (nodes g) ac)
231  in fixpoint (subjectAffectsq g l) [];;
232
233
234
235(*********************************************************************************************************************)
236
237
238(* clear_infoflow g removes all self-edges in the infoflow policy graph g *)
239
240let rec clear_infoflow =function
241|[] ->[]
242|a::l -> let (p,q)=a in
243           if (p=q) then clear_infoflow l
244                    else a::(clear_infoflow l);;
245
246
247
248(* infoflow g computes the translation of the authority graph g into its infoflow policy without deleting the self edges *)
249
250let infoflow g =
251  let rec aux g list l = match list with
252    |[] -> []
253    |x::li -> let b = inter_non_empty (subjectAffects g l) (subjectReads g x) in
254                if b then (l,x)::(aux g li l)
255                     else aux g li l
256  in let res = map (aux g (nodes g)) (nodes g)
257  in unite res;;
258
259
260(*********************************************************************************************************************)
261
262
263(* we compute info_flow for several examples *)
264
265(* we define two authority graphs *)
266
267let g1=[("L",Write,"SP");("L",Read,"SP");("L",ASyncSend,"AEP");("H",Read,"SP");("H",Receive,"AEP")];;
268let g2=[("T",ASyncSend,"AEP1");("T",ASyncSend,"AEP2");("CTR",Receive,"AEP1");("CTR",Read,"C");("CTR",Write,"C");
269        ("C",Read,"CTR");("C",Write,"CTR");("CTR",SyncSend,"EP");("RM",Receive,"EP");("RM",Receive,"AEP2")];;
270
271
272(* Example 1 *)
273
274nodes g1;;
275
276map (fun l -> subjectReads g2 l) (nodes g2);;
277map (fun l-> subjectAffects g2 l) (nodes g2);;
278
279infoflow g1;;
280
281let g1_complete = add_selfedges g1 in infoflow (g1@g1_complete);;
282
283let g1_complete = add_selfedges g1 in clear_infoflow (infoflow (g1@g1_complete));;
284
285
286(* Example 2 *)
287
288nodes g2;;
289
290map (fun l -> subjectReads g2 l) (nodes g2);;
291map (fun l-> subjectAffects g2 l) (nodes g2);;
292
293infoflow g2;;
294
295let g2_complete = add_selfedges g2 in infoflow (g2@g2_complete);;
296
297let g2_complete = add_selfedges g2 in clear_infoflow (infoflow (g2@g2_complete));;
298
299
300(*********************************************************************************************************************)
301(*********************************************************************************************************************)
302
303
304(* this new section deals with representing the info_flow graphs *)
305
306(* we first implement Tarjan's algorithm to find the partition of a oriented graph into strongly connected components *)
307
308
309(*********************************************************************************************************************)
310
311(* first some basic functions *)
312
313(* find x t return true if x is in t and else otherwise *)
314
315let find x t =
316  let n = vect_length t in
317    let rec aux x t i = match (i=n) with
318      |true -> false
319      |false -> (t.(i) = x) || aux x t (i+1)
320  in aux x t 1;;
321
322
323
324(* we define the exception NotFound *)
325
326exception NotFound;;
327
328
329
330(* find_index x t returns the index of x in t if t contains x, and raises NotFound otherwise *)
331
332let find_index x t=
333  let n = vect_length t in
334    let rec aux x t i = match (i=n) with
335      |true -> raise NotFound
336      |false ->  if (t.(i) = x) then i else aux x t (i+1)
337  in aux x t 0;;
338
339
340
341(* successors g x returns the successors of x in g in an infoflow graph *)
342
343let successors g x =
344  let rec aux g x h = match g with
345    |[] -> simp_list h
346    |(a,c)::l -> if (a=x) then aux l x (c::h) else aux l x h
347  in aux g x [];;
348
349
350
351(* apply f l applies recursively function f, of type 'a -> Unit, on the elements of l *)
352
353let rec apply f = function
354  |[] -> ()
355  |a::l -> (f a;apply f l);;
356
357
358(* nodes_infoflow g computes the list of nodes in the infoflow graph g *)
359
360let rec nodes_infoflow g =
361  let rec nodes_aux g = match g with
362    |[] -> []
363    |(a,b)::l->a::b::(nodes_aux l)
364  in simp_list (nodes_aux g);;
365
366
367
368(*********************************************************************************************************************)
369
370
371(* we define the tarjanp function, computing the partition of the infoflow graph g in strongly connected components *)
372(* BEWARE : THIS FUNCTION USES GRAPHS LABELLED BY int *)
373
374
375let tarjanp g =
376  let n = list_length (nodes_infoflow g) in
377  let num = ref 0 in
378  let p = new () in
379  let partition = ref [] in
380  let numt = make_vect n (-1) in
381  let numAccessible = make_vect n (-1) in
382  let dans_P = make_vect n false in
383  let rec parcours g v = begin
384    numt.(v) <- (!num);
385    numAccessible.(v) <- (!num);
386    num := 1 + (!num);
387    push v p;
388    dans_P.(v) <- true;
389    let l = successors g v in
390    let rec aux = function
391      |[] -> ()
392      |w::rest -> begin
393                  if (numt.(w) = -1)
394                  then (
395                       parcours g w;
396                       numAccessible.(v) <- min (numAccessible.(v)) (numAccessible.(w))
397                       )
398                  else if (dans_P.(w))
399                       then numAccessible.(v) <- min (numAccessible.(v)) (numt.(w))
400                       else ();
401                  aux rest
402                  end
403    in aux l;
404    if (numAccessible.(v) = numt.(v))
405    then let C = ref [] in
406         let w = ref (-1) in
407         begin
408         w := pop p;
409         dans_P.(!w) <- false;
410         C := (!w)::(!C);
411         while (v<>(!w)) do
412           (
413           w := pop p;
414           dans_P.(!w) <- false;
415           C := (!w)::(!C)
416           )
417                         done;
418    partition := (!C)::(!partition)
419         end
420 end
421  in
422  apply (fun v -> (if (numt.(v)=(-1)) then parcours g v)) (nodes_infoflow g);
423  !partition;;
424
425
426
427(* we define 2 functions mapping the labels in the infoflow graph to int, and back to string *)
428
429let rec string2int_labels name_t = function
430|[] -> []
431|(x,y)::l -> let i = find_index x name_t in
432               let j = find_index y name_t in
433               (i,j)::(string2int_labels name_t l);;
434
435
436let rec int2string_labels name_t = function
437|[] -> []
438|i::l -> name_t.(i)::(int2string_labels name_t l);;
439
440
441
442(* tarjan g, where g is an infoflow graph, computes the partition of g in strongly connected components *)
443
444let tarjan g =
445  let n = list_length (nodes_infoflow g) in
446  let name_tab = vect_of_list (nodes_infoflow g) in
447  let gi = string2int_labels name_tab g in
448  let p = tarjanp gi in
449  map (int2string_labels name_tab) p;;
450
451
452
453(* Examples *)
454
455tarjan (infoflow g1);;
456tarjan (infoflow g2);;
457
458
459
460(*********************************************************************************************************************)
461
462
463(* We now build the reduced graph, by building the edges between the new nodes *)
464
465(* exists_edge_info_flow g u v checks whether there is an edge in g from an element of node list u to an element of node list v *)
466
467let rec exists_edge_infoflow g u v = match g with
468  |[] -> false
469  |(x,y)::l -> ((is_in u x) && (is_in v y))||exists_edge_infoflow l u v;;
470
471
472
473(* simp_infoflow g computes the reduced (or simplified) infoflow graph, where the new nodes are the strongly connected components from the original infoflow policy *)
474
475let simp_infoflow g =
476  let rec search_edges g u v = match u with
477    |[] -> []
478    |a::l -> if (exists_edge_infoflow g a v) then (a,v)::(search_edges g l v) else (search_edges g l v)
479  in let t = tarjan g in
480  simp_list (unite (map (search_edges g t) t));;
481
482
483
484(* Examples *)
485
486simp_infoflow (infoflow g1);;
487simp_infoflow (infoflow g2);;
488
489
490clear_infoflow (simp_infoflow (infoflow g1));;
491clear_infoflow (simp_infoflow (infoflow g2));;
492