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