comparison src/iflow.sml @ 1207:ae3036773768

Introduced the known() predicate
author Adam Chlipala <adamc@hcoop.net>
date Tue, 06 Apr 2010 09:51:36 -0400
parents 772760df4c4c
children b5a4c5407ae0
comparison
equal deleted inserted replaced
1206:772760df4c4c 1207:ae3036773768
27 27
28 structure Iflow :> IFLOW = struct 28 structure Iflow :> IFLOW = struct
29 29
30 open Mono 30 open Mono
31 31
32 structure IS = IntBinarySet
32 structure IM = IntBinaryMap 33 structure IM = IntBinaryMap
33 34
34 structure SS = BinarySetFn(struct 35 structure SS = BinarySetFn(struct
35 type ord_key = string 36 type ord_key = string
36 val compare = String.compare 37 val compare = String.compare
62 | Recd of (string * exp) list 63 | Recd of (string * exp) list
63 | Proj of exp * string 64 | Proj of exp * string
64 | Finish 65 | Finish
65 66
66 datatype reln = 67 datatype reln =
67 Sql of string 68 Known
69 | Sql of string
68 | Eq 70 | Eq
69 71
70 datatype prop = 72 datatype prop =
71 True 73 True
72 | False 74 | False
73 | Unknown 75 | Unknown
74 | And of prop * prop 76 | And of prop * prop
75 | Or of prop * prop 77 | Or of prop * prop
76 | Reln of reln * exp list 78 | Reln of reln * exp list
77 | Select of int * lvar * lvar * prop * exp 79 | Select of int * lvar * lvar * prop * exp
80
81 local
82 open Print
83 val string = PD.string
84 in
85
86 fun p_exp e =
87 case e of
88 Const p => Prim.p_t p
89 | Var n => string ("x" ^ Int.toString n)
90 | Lvar n => string ("X" ^ Int.toString n)
91 | Func (f, es) => box [string (f ^ "("),
92 p_list p_exp es,
93 string ")"]
94 | Recd xes => box [string "{",
95 p_list (fn (x, e) => box [string "x",
96 space,
97 string "=",
98 space,
99 p_exp e]) xes,
100 string "}"]
101 | Proj (e, x) => box [p_exp e,
102 string ("." ^ x)]
103 | Finish => string "FINISH"
104
105 fun p_reln r es =
106 case r of
107 Known =>
108 (case es of
109 [e] => box [string "known(",
110 p_exp e,
111 string ")"]
112 | _ => raise Fail "Iflow.p_reln: Known")
113 | Sql s => box [string (s ^ "("),
114 p_list p_exp es,
115 string ")"]
116 | Eq =>
117 (case es of
118 [e1, e2] => box [p_exp e1,
119 space,
120 string "=",
121 space,
122 p_exp e2]
123 | _ => raise Fail "Iflow.p_reln: Eq")
124
125 fun p_prop p =
126 case p of
127 True => string "True"
128 | False => string "False"
129 | Unknown => string "??"
130 | And (p1, p2) => box [string "(",
131 p_prop p1,
132 string ")",
133 space,
134 string "&&",
135 space,
136 string "(",
137 p_prop p2,
138 string ")"]
139 | Or (p1, p2) => box [string "(",
140 p_prop p1,
141 string ")",
142 space,
143 string "||",
144 space,
145 string "(",
146 p_prop p2,
147 string ")"]
148 | Reln (r, es) => p_reln r es
149 | Select (n1, n2, n3, p, e) => box [string ("select(x" ^ Int.toString n1
150 ^ ",X" ^ Int.toString n2
151 ^ ",X" ^ Int.toString n3
152 ^ "){"),
153 p_prop p,
154 string "}{",
155 p_exp e,
156 string "}"]
157
158 end
78 159
79 local 160 local
80 val count = ref 1 161 val count = ref 1
81 in 162 in
82 fun newLvar () = 163 fun newLvar () =
286 true 367 true
287 else 368 else
288 (restore saved; 369 (restore saved;
289 (*raise Imply (Reln (Eq, es1), Reln (Eq, es2));*) 370 (*raise Imply (Reln (Eq, es1), Reln (Eq, es2));*)
290 eq (x1, y2) andalso eq (y1, x2)) 371 eq (x1, y2) andalso eq (y1, x2))
372 end
373 | _ => false)
374 | (Known, Known) =>
375 (case (es1, es2) of
376 ([e1], [e2]) =>
377 let
378 fun walk e2 =
379 eq (e1, e2) orelse
380 case e2 of
381 Proj (e2, _) => walk e2
382 | _ => false
383 in
384 walk e2
291 end 385 end
292 | _ => false) 386 | _ => false)
293 | _ => false 387 | _ => false
294 388
295 fun imply (p1, p2) = 389 fun imply (p1, p2) =
342 | Exp of Mono.exp 436 | Exp of Mono.exp
343 437
344 fun chunkify e = 438 fun chunkify e =
345 case #1 e of 439 case #1 e of
346 EPrim (Prim.String s) => [String s] 440 EPrim (Prim.String s) => [String s]
347 | EStrcat (e1, e2) => chunkify e1 @ chunkify e2 441 | EStrcat (e1, e2) =>
442 let
443 val chs1 = chunkify e1
444 val chs2 = chunkify e2
445 in
446 case chs2 of
447 String s2 :: chs2' =>
448 (case List.last chs1 of
449 String s1 => List.take (chs1, length chs1 - 1) @ String (s1 ^ s2) :: chs2'
450 | _ => chs1 @ chs2)
451 | _ => chs1 @ chs2
452 end
348 | _ => [Exp e] 453 | _ => [Exp e]
349 454
350 type 'a parser = chunk list -> ('a * chunk list) option 455 type 'a parser = chunk list -> ('a * chunk list) option
351 456
352 fun always v chs = SOME (v, chs) 457 fun always v chs = SOME (v, chs)
382 487
383 fun alt p1 p2 chs = 488 fun alt p1 p2 chs =
384 case p1 chs of 489 case p1 chs of
385 NONE => p2 chs 490 NONE => p2 chs
386 | v => v 491 | v => v
492
493 fun altL ps =
494 case rev ps of
495 [] => (fn _ => NONE)
496 | p :: ps =>
497 foldl (fn (p1, p2) => alt p1 p2) p ps
387 498
388 fun opt p chs = 499 fun opt p chs =
389 case p chs of 500 case p chs of
390 NONE => SOME (NONE, chs) 501 NONE => SOME (NONE, chs)
391 | SOME (v, chs) => SOME (SOME v, chs) 502 | SOME (v, chs) => SOME (SOME v, chs)
423 val debug = ref false 534 val debug = ref false
424 535
425 fun log name p chs = 536 fun log name p chs =
426 (if !debug then 537 (if !debug then
427 case chs of 538 case chs of
428 String s :: [] => print (name ^ ": " ^ s ^ "\n") 539 String s :: _ => print (name ^ ": " ^ s ^ "\n")
429 | _ => print (name ^ ": blocked!\n") 540 | _ => print (name ^ ": blocked!\n")
430 else 541 else
431 (); 542 ();
432 p chs) 543 p chs)
433 544
434 fun list p chs = 545 fun list p chs =
435 (alt (wrap (follow p (follow (ws (const ",")) (list p))) 546 altL [wrap (follow p (follow (ws (const ",")) (list p)))
436 (fn (v, ((), ls)) => v :: ls)) 547 (fn (v, ((), ls)) => v :: ls),
437 (alt (wrap (ws p) (fn v => [v])) 548 wrap (ws p) (fn v => [v]),
438 (always []))) chs 549 always []] chs
439 550
440 val ident = keep (fn ch => Char.isAlphaNum ch orelse ch = #"_") 551 val ident = keep (fn ch => Char.isAlphaNum ch orelse ch = #"_")
441 552
442 val t_ident = wrap ident (fn s => if String.isPrefix "T_" s then 553 val t_ident = wrap ident (fn s => if String.isPrefix "T_" s then
443 String.extract (s, 2, NONE) 554 String.extract (s, 2, NONE)
459 570
460 datatype sqexp = 571 datatype sqexp =
461 SqConst of Prim.t 572 SqConst of Prim.t
462 | Field of string * string 573 | Field of string * string
463 | Binop of Rel * sqexp * sqexp 574 | Binop of Rel * sqexp * sqexp
464 575 | SqKnown of sqexp
465 val sqbrel = alt (wrap (const "=") (fn () => Exps (fn (e1, e2) => Reln (Eq, [e1, e2])))) 576 | Inj of Mono.exp
466 (alt (wrap (const "AND") (fn () => Props And)) 577
467 (wrap (const "OR") (fn () => Props Or))) 578 val sqbrel = altL [wrap (const "=") (fn () => Exps (fn (e1, e2) => Reln (Eq, [e1, e2]))),
579 wrap (const "AND") (fn () => Props And),
580 wrap (const "OR") (fn () => Props Or)]
468 581
469 datatype ('a, 'b) sum = inl of 'a | inr of 'b 582 datatype ('a, 'b) sum = inl of 'a | inr of 'b
470 583
471 fun int chs = 584 fun int chs =
472 case chs of 585 case chs of
485 end 598 end
486 | _ => NONE 599 | _ => NONE
487 600
488 val prim = wrap (follow (wrap int Prim.Int) (opt (const "::int8"))) #1 601 val prim = wrap (follow (wrap int Prim.Int) (opt (const "::int8"))) #1
489 602
603 fun known' chs =
604 case chs of
605 Exp (EFfi ("Basis", "sql_known"), _) :: chs => SOME ((), chs)
606 | _ => NONE
607
608 fun sqlify chs =
609 case chs of
610 Exp (EFfiApp ("Basis", f, [e]), _) :: chs =>
611 if String.isPrefix "sqlify" f then
612 SOME (e, chs)
613 else
614 NONE
615 | _ => NONE
616
490 fun sqexp chs = 617 fun sqexp chs =
491 log "sqexp" 618 log "sqexp"
492 (alt 619 (altL [wrap prim SqConst,
493 (wrap prim SqConst) 620 wrap sitem Field,
494 (alt 621 wrap known SqKnown,
495 (wrap sitem Field) 622 wrap sqlify Inj,
496 (wrap 623 wrap (follow (ws (const "("))
497 (follow (ws (const "(")) 624 (follow (wrap
498 (follow (wrap 625 (follow sqexp
499 (follow sqexp 626 (alt
500 (alt 627 (wrap
501 (wrap 628 (follow (ws sqbrel)
502 (follow (ws sqbrel) 629 (ws sqexp))
503 (ws sqexp)) 630 inl)
504 inl) 631 (always (inr ()))))
505 (always (inr ())))) 632 (fn (e1, sm) =>
506 (fn (e1, sm) => 633 case sm of
507 case sm of 634 inl (bo, e2) => Binop (bo, e1, e2)
508 inl (bo, e2) => Binop (bo, e1, e2) 635 | inr () => e1))
509 | inr () => e1)) 636 (const ")")))
510 (const ")"))) 637 (fn ((), (e, ())) => e)])
511 (fn ((), (e, ())) => e)))) 638 chs
512 chs 639
513 640 and known chs = wrap (follow known' (follow (const "(") (follow sqexp (const ")"))))
514 val select = wrap (follow (const "SELECT ") (list sitem)) 641 (fn ((), ((), (e, ()))) => e) chs
515 (fn ((), ls) => ls) 642
643 val select = log "select"
644 (wrap (follow (const "SELECT ") (list sitem))
645 (fn ((), ls) => ls))
516 646
517 val fitem = wrap (follow uw_ident 647 val fitem = wrap (follow uw_ident
518 (follow (const " AS ") 648 (follow (const " AS ")
519 t_ident)) 649 t_ident))
520 (fn (t, ((), f)) => (t, f)) 650 (fn (t, ((), f)) => (t, f))
521 651
522 val from = wrap (follow (const "FROM ") (list fitem)) 652 val from = log "from"
523 (fn ((), ls) => ls) 653 (wrap (follow (const "FROM ") (list fitem))
654 (fn ((), ls) => ls))
524 655
525 val wher = wrap (follow (ws (const "WHERE ")) sqexp) 656 val wher = wrap (follow (ws (const "WHERE ")) sqexp)
526 (fn ((), ls) => ls) 657 (fn ((), ls) => ls)
527 658
528 val query = wrap (follow (follow select from) (opt wher)) 659 val query = log "query"
529 (fn ((fs, ts), wher) => {Select = fs, From = ts, Where = wher}) 660 (wrap (follow (follow select from) (opt wher))
530 661 (fn ((fs, ts), wher) => {Select = fs, From = ts, Where = wher}))
531 fun queryProp rv oe e = 662
663 fun queryProp env rv oe e =
532 case parse query e of 664 case parse query e of
533 NONE => (print "Crap\n"; Unknown) 665 NONE => (print ("Warning: Information flow checker can't parse SQL query at "
666 ^ ErrorMsg.spanToString (#2 e) ^ "\n");
667 Unknown)
534 | SOME r => 668 | SOME r =>
535 let 669 let
536 val p = 670 val p =
537 foldl (fn ((t, v), p) => 671 foldl (fn ((t, v), p) =>
538 And (p, 672 And (p,
551 | Binop (bo, e1, e2) => 685 | Binop (bo, e1, e2) =>
552 inr (case (bo, expIn e1, expIn e2) of 686 inr (case (bo, expIn e1, expIn e2) of
553 (Exps f, inl e1, inl e2) => f (e1, e2) 687 (Exps f, inl e1, inl e2) => f (e1, e2)
554 | (Props f, inr p1, inr p2) => f (p1, p2) 688 | (Props f, inr p1, inr p2) => f (p1, p2)
555 | _ => Unknown) 689 | _ => Unknown)
690 | SqKnown e =>
691 inr (case expIn e of
692 inl e => Reln (Known, [e])
693 | _ => Unknown)
694 | Inj e =>
695 let
696 fun deinj (e, _) =
697 case e of
698 ERel n => List.nth (env, n)
699 | EField (e, f) => Proj (deinj e, f)
700 | _ => raise Fail "Iflow: non-variable injected into query"
701 in
702 inl (deinj e)
703 end
556 704
557 val p = case #Where r of 705 val p = case #Where r of
558 NONE => p 706 NONE => p
559 | SOME e => 707 | SOME e =>
560 case expIn e of 708 case expIn e of
705 853
706 val (b, st') = evalExp (Var acc :: Var r :: env) (b, st') 854 val (b, st') = evalExp (Var acc :: Var r :: env) (b, st')
707 855
708 val r' = newLvar () 856 val r' = newLvar ()
709 val acc' = newLvar () 857 val acc' = newLvar ()
710 val qp = queryProp r' NONE q 858 val qp = queryProp env r' NONE q
711 859
712 val doSubExp = subExp (r, r') o subExp (acc, acc') 860 val doSubExp = subExp (r, r') o subExp (acc, acc')
713 val doSubProp = subProp (r, r') o subProp (acc, acc') 861 val doSubProp = subProp (r, r') o subProp (acc, acc')
714 862
715 val p = doSubProp (#2 st') 863 val p = doSubProp (#2 st')
735 | ESpawn _ => default () 883 | ESpawn _ => default ()
736 end 884 end
737 885
738 fun check file = 886 fun check file =
739 let 887 let
888 val exptd = foldl (fn ((d, _), exptd) =>
889 case d of
890 DExport (_, _, n, _, _, _) => IS.add (exptd, n)
891 | _ => exptd) IS.empty file
892
740 fun decl ((d, _), (vals, pols)) = 893 fun decl ((d, _), (vals, pols)) =
741 case d of 894 case d of
742 DVal (x, _, _, e, _) => 895 DVal (_, n, _, e, _) =>
743 let 896 let
744 fun deAbs (e, env, nv) = 897 val isExptd = IS.member (exptd, n)
898
899 fun deAbs (e, env, nv, p) =
745 case #1 e of 900 case #1 e of
746 EAbs (_, _, _, e) => deAbs (e, Var nv :: env, nv + 1) 901 EAbs (_, _, _, e) => deAbs (e, Var nv :: env, nv + 1,
747 | _ => (e, env, nv) 902 if isExptd then
748 903 And (p, Reln (Known, [Var nv]))
749 val (e, env, nv) = deAbs (e, [], 1) 904 else
750 905 p)
751 val (e, (_, p, sent)) = evalExp env (e, (nv, True, [])) 906 | _ => (e, env, nv, p)
907
908 val (e, env, nv, p) = deAbs (e, [], 1, True)
909
910 val (e, (_, p, sent)) = evalExp env (e, (nv, p, []))
752 in 911 in
753 ((x, e, p, sent) :: vals, pols) 912 (sent @ vals, pols)
754 end 913 end
755 914
756 | DPolicy (PolQuery e) => (vals, queryProp 0 (SOME (Var 0)) e :: pols) 915 | DPolicy (PolQuery e) => (vals, queryProp [] 0 (SOME (Var 0)) e :: pols)
757 916
758 | _ => (vals, pols) 917 | _ => (vals, pols)
759 918
760 val () = reset () 919 val () = reset ()
761 920
762 val (vals, pols) = foldl decl ([], []) file 921 val (vals, pols) = foldl decl ([], []) file
763 in 922 in
764 app (fn (name, _, _, sent) => 923 app (fn (loc, e, p) =>
765 app (fn (loc, e, p) => 924 let
766 let 925 val p = And (p, Reln (Eq, [Var 0, e]))
767 val p = And (p, Reln (Eq, [Var 0, e])) 926 in
768 in 927 if List.exists (fn pol => imply (p, pol)) pols then
769 if List.exists (fn pol => imply (p, pol)) pols then 928 ()
770 () 929 else
771 else 930 (ErrorMsg.errorAt loc "The information flow policy may be violated here.";
772 ErrorMsg.errorAt loc "The information flow policy may be violated here." 931 Print.preface ("The state satisifes this predicate:", p_prop p))
773 end) sent) vals 932 end) vals
774 end 933 end
775 934
776 end 935 end