Inference of Expressive Declassification Policies
Jeff Vaughan Stephen Chong
IEEE Security and Privacy May 23, 2011 @output "out" @output "out" @output "out" @output "out" @input "authCheckOk" @input "secret" @input "secret" @input "secret" @input "secret"
class Client { return e; return true; throw new IllegalArgumentException(); } } } public static String fakeReadingArgs(int i) } if(i==0){ throws java.util.NoSuchElementException { } if (r == MOLE) { return this.next; if(i<42) { return null; return true; } return "bork bork"; } } return next.removePersistent(i−1); } else { } throw new java.util.NoSuchElementException(); public Role readerOf(String key) { return (s == r); } if (lookup(key) != null) { } public void set(int i, Object o) { } return lookup(key).getReader(); if(i < 0){ } } throw new IllegalArgumentException(); public static void main(String args[]){ return null; import java.util.Iterator; } String uname; } import java.util.NoSuchElementException; if(i==0){ String pwd; this.contents = o; String key; public String secretOf(String key) { public class SimpleArrayList implements Iterable { } else { try{ if (lookup(key) != null) { this.next.set(i−1, o); uname = fakeReadingArgs(0); return lookup(key).getData(); List contents; } pwd = fakeReadingArgs(1); } } key = fakeReadingArgs(2); return null; SimpleArrayList() {this.contents = new Nil();} } } public Object head() throws NoSuchElementException { catch (Exception e){ } int size() { return contents.size(); } return this.contents; System.out.println( class DbEntry{ boolean isEmpty() {return contents.isEmpty(); } } private String key; void clear() { this.contents = new Nil(); } "Useage \"java Client
class Client { return e; return true; throw new IllegalArgumentException(); } } } public static String fakeReadingArgs(int i) } if(i==0){ throws java.util.NoSuchElementException { } if (r == MOLE) { return this.next; if(i<42) { return null; return true; } return "bork bork"; } } return next.removePersistent(i−1); } else { } throw new java.util.NoSuchElementException(); public Role readerOf(String key) { return (s == r); } if (lookup(key) != null) { } public void set(int i, Object o) { } return lookup(key).getReader(); if(i < 0){ } } throw new IllegalArgumentException(); public static void main(String args[]){ return null; import java.util.Iterator; } String uname; } import java.util.NoSuchElementException; if(i==0){ String pwd; this.contents = o; String key; public String secretOf(String key) { public class SimpleArrayList implements Iterable { } else { try{ if (lookup(key) != null) { this.next.set(i−1, o); uname = fakeReadingArgs(0); return lookup(key).getData(); Inferred policyList contents; } pwd = fakeReadingArgs(1); } } key = fakeReadingArgs(2); return null; SimpleArrayList() {this.contents = new Nil();} } } public Object head() throws NoSuchElementException { catch (Exception e){ } int size() { return contents.size(); } return this.contents; System.out.println( class DbEntry{ boolean isEmpty() {return contents.isEmpty(); } } private String key; 7→ void clear() { this.contents = new Nil(); } "Useage \"java Client
X policy This work
Goal: Workflow of iterative policy refinement via inference
code policy
{X,X}
JIF [Myers et. al. ’03], FlowCaml [Simonet ’03], . . . 3/24 Goal: Workflow of iterative policy refinement via inference
code policy code
{X,X} X
JIF [Myers et. al. ’03], policy FlowCaml [Simonet ’03], . . . This work 3/24 Goal: Analysis suitable for mostly unmodified, legacy Java programs
Low annotation burden Deep analysis of practical Java features: exceptions, heap allocated objects, etc. Security guarantees scale with effort
security
effort
4/24 The central tension:
expressive effective policies analysis
5/24 Outline
1 Policies
2 Inference
3 Implementation and Validation
6/24 Inferred policy
stdout 7→ Reveal( stdin[0] )
Reveal policies describe what information is released
x = @input "stdin" readln(); y = x; println(@output "stdout" y);
7/24 Inferred policy
stdout 7→ Reveal( stdin[0] )
Reveal policies describe what information is released
x = @input "stdin" readln(); y = x; println(@output "stdout" y);
7/24 Reveal policies describe what information is released
x = @input "stdin" readln(); y = x; println(@output "stdout" y);
Inferred policy
stdout 7→ Reveal( stdin[0] )
7/24 Inferred policy
stdout 7→ Reveal( H[1] == null )
H[0] — the most recent H input H[1] — the second most recent H input . .
Precise input expressions name inputs and derived data exactly
String read(){ return @input "H" readln(); }
x = read(); y = read(); println(@output "stdout" (x == null));
8/24 Inferred policy
stdout 7→ Reveal( H[1] == null )
H[0] — the most recent H input H[1] — the second most recent H input . .
Precise input expressions name inputs and derived data exactly
String read(){ return @input "H" readln(); }
x = read(); y = read(); println(@output "stdout" (x == null));
8/24 Precise input expressions name inputs and derived data exactly
String read(){ return @input "H" readln(); }
x = read(); y = read(); println(@output "stdout" (x == null));
Inferred policy
stdout 7→ Reveal( H[1] == null )
H[0] — the most recent H input H[1] — the second most recent H input . .
8/24 Inferred policy
out 7→ Reveal( in[0+] )
in[0+] — information from any in input in[1+] — info. from the second most recent and older in inputs . .
Imprecise expressions name multiple inputs sharing a label
int i = 0; while (i <= 100) i += parse(@input "in" readln()); } println(@output "out" i);
9/24 Imprecise expressions name multiple inputs sharing a label
int i = 0; while (i <= 100) i += parse(@input "in" readln()); } println(@output "out" i);
Inferred policy
out 7→ Reveal( in[0+] )
in[0+] — information from any in input in[1+] — info. from the second most recent and older in inputs . . 9/24 Conditional policies describe when information is released
secret = @input "secret" ... password = @input "password" ... guess = @input "guess" ...
if (guess == password) { println(@output "stdout" secret); }
Policy?
stdout 7→ Reveal( secret[0], guess[0], password[0] )
10/24
Inferred policy
stdout 7→ if ( guess[0] == password[0] ) then Reveal( secret[0] ) Conditional policies describe when information is released
secret = @input "secret" ... password = @input "password" ... guess = @input "guess" ...
if (guess == password) { println(@output "stdout" secret); }
Policy?Inferred policy
stdout 7→ Revealif ( guess[0]( secret[0], == password[0] guess[0], password[0] ) then ) Reveal( secret[0] )
10/24 Inferred policy
out 7→ if-executed safe_release(String) then Reveal(in[0])
Track policies describe where information is released String safe_release(String x) @track { if (/∗ auth check ∗/) { return x; } else { return ""; } } x = @input "in" readln(); y = safe_release(x); println(@output "out" y);
11/24 Inferred policy
out 7→ if-executed safe_release(String) then Reveal(in[0])
Track policies describe where information is released String safe_release(String x) @track { if (/∗ auth check ∗/) { return x; } else { return ""; } } x = @input "in" readln(); y = safe_release(x); println(@output "out" y);
11/24 Track policies describe where information is released String safe_release(String x) @track { if (/∗ auth check ∗/) { return x; } else { return ""; } } x = @input "in" readln(); y = safe_release(x); println(@output "out" y);
Inferred policy
out 7→ if-executed safe_release(String) then Reveal(in[0])
11/24 Inference
12/24 (pc1, Γ1)
(pc2, Γ2) (pc3, Γ3)
(pc4, Γ4)
. . ⇒
if (x < y)
x = x + 1;
z = x; X Natural handling of strong updates. . X Convenient for calculating non-syntactic . control dependencies.
Inference algorithm is based on dataflow analysis
if (x < y){ x = x + 1; } z = x;
13/24 (pc1, Γ1)
(pc2, Γ2) (pc3, Γ3)
X Natural handling of strong updates. X Convenient for calculating non-syntactic (pc4, Γ4) control dependencies.
Inference algorithm is based on dataflow analysis
if (x < y){ . x = x + 1; . } ⇒ z = x; if (x < y)
x = x + 1;
z = x;
. .
13/24 X Natural handling of strong updates. X Convenient for calculating non-syntactic control dependencies.
Inference algorithm is based on dataflow analysis
if (x < y){ . x = x + 1; . } ⇒ (pc1, Γ1) z = x; if (x < y)
(pc2, Γ2) (pc3, Γ3)
x = x + 1;
z = x;
. (pc , Γ ) . 4 4
13/24 Inference algorithm is based on dataflow analysis
if (x < y){ . x = x + 1; . } ⇒ (pc1, Γ1) z = x; if (x < y)
(pc2, Γ2) (pc3, Γ3)
x = x + 1;
z = x; X Natural handling of strong updates. . (pc , Γ ) X Convenient for calculating non-syntactic . 4 4 control dependencies. 13/24 Contexts (pc, Γ) approximates information flow
Location context: information content of fields or heap locations.
Γ: Location * Policy Program counter: what each branch taken to a program point reveals.
pc : BranchId * Policy ∪ PIE
Location = abstract vars and refs PIE = precise input exps. BranchId = static branch ids Policy = policies
14/24 1 Calculate explicit flows. explicit = Γ(x)
2 Calculate implicit, imprecise flows. G implicit = (range(pc) ∩ Policy) (pc, Γ0) 3 Calculate dominating precise input exps.
{d1, d2,..., dn} = range(pc) ∩ PIE
4 Assemble a policy.
pol = if d1&& d2 && .... dn then (explicit t implicit)
5 Update the dataflow graph. Γ0 = Γ[ z 7→ pol ]
Example: Updating a context for an assignment node
(pc, Γ)
z = x;
15/24 2 Calculate implicit, imprecise flows. G implicit = (range(pc) ∩ Policy) (pc, Γ0) 3 Calculate dominating precise input exps.
{d1, d2,..., dn} = range(pc) ∩ PIE
4 Assemble a policy.
pol = if d1&& d2 && .... dn then (explicit t implicit)
5 Update the dataflow graph. Γ0 = Γ[ z 7→ pol ]
Example: Updating a context for an assignment node
1 Calculate explicit flows. (pc, Γ) explicit = Γ(x)
z = x;
15/24 (pc, Γ0) 3 Calculate dominating precise input exps.
{d1, d2,..., dn} = range(pc) ∩ PIE
4 Assemble a policy.
pol = if d1&& d2 && .... dn then (explicit t implicit)
5 Update the dataflow graph. Γ0 = Γ[ z 7→ pol ]
Example: Updating a context for an assignment node
1 Calculate explicit flows. (pc, Γ) explicit = Γ(x)
z = x; 2 Calculate implicit, imprecise flows. G implicit = (range(pc) ∩ Policy)
15/24 (pc, Γ0)
4 Assemble a policy.
pol = if d1&& d2 && .... dn then (explicit t implicit)
5 Update the dataflow graph. Γ0 = Γ[ z 7→ pol ]
Example: Updating a context for an assignment node
1 Calculate explicit flows. (pc, Γ) explicit = Γ(x)
z = x; 2 Calculate implicit, imprecise flows. G implicit = (range(pc) ∩ Policy)
3 Calculate dominating precise input exps.
{d1, d2,..., dn} = range(pc) ∩ PIE
15/24 (pc, Γ0)
5 Update the dataflow graph. Γ0 = Γ[ z 7→ pol ]
Example: Updating a context for an assignment node
1 Calculate explicit flows. (pc, Γ) explicit = Γ(x)
z = x; 2 Calculate implicit, imprecise flows. G implicit = (range(pc) ∩ Policy)
3 Calculate dominating precise input exps.
{d1, d2,..., dn} = range(pc) ∩ PIE
4 Assemble a policy.
pol = if d1&& d2 && .... dn then (explicit t implicit)
15/24 Example: Updating a context for an assignment node
1 Calculate explicit flows. (pc, Γ) explicit = Γ(x)
z = x; 2 Calculate implicit, imprecise flows. G implicit = (range(pc) ∩ Policy) (pc, Γ0) 3 Calculate dominating precise input exps.
{d1, d2,..., dn} = range(pc) ∩ PIE
4 Assemble a policy.
pol = if d1&& d2 && .... dn then (explicit t implicit)
5 Update the dataflow graph. 0 Γ = Γ[ z 7→ pol ] 15/24 Implementation and Validation
16/24 We prototyped an implementation that analyses Java 1.4 programs
Implementation (35,100 lines of Java code) extends the Polyglot compiler framework. [Nystrom, Clarkson, & Myers ’03] Program analyses refine security inference: Object-sensitive pointer analysis reasons precisely about non-aliased objects, preventing label creep. Post dominance analysis determines identifies where pc levels may be safely lowered. Precise type and exception analysis simplifies control flow graph by ruling out spurious exceptions (e.g. from casts that always succeed).
17/24 Case studies: successful inference of interesting information flows
Computer Inputs sanitized before display. psychiatrist
Interactive password Passwords only revealed via (simulated) manager cryptography.
Access-controlled Information release governed by reference key-value store monitor.
Go Fish The computer doesn’t cheat.
Battleship game The computer doesn’t cheat. [Jif]
Private keys influence outputs appropriately Mental poker . [Askarov & Sabelfeld ’05] 18/24 Computer player, p2 Human player, p1 @input "p1 board"
p2 query 7→ if (p2 query ok[0]) then Reveal(p2 query ok[1+], p2 hit p1?[0+], p1 hit p2?[0+])
Computer (p2) player’s queries only depend on public data.
Sample policy: Battleship
private PwdTableEntry(String uname,public String static pwd, final Role Role role){ MOLE = new Role("mole"); return lookup(key).getReader(); this.uname=uname; public static final Role TECH_GUY = new Role("tech"); return lookup(key).getReader(); int size() { return contents.size(); } } this.pwd=pwd; } boolean isEmpty() {return contents.isEmpty(); } return null; this.role=role; private final String id; return null; void clear() { this.contents = new Nil(); } } } private Role(String id){ } } this.id = id; private static abstract class List { public String secretOf(String key) { } public String secretOf(String key) { private List() { } if (lookup(key) != null) { private static SimpleArrayList pwds; if (lookup(key) != null) { abstract int size(); return lookup(key).getData(); public static boolean lteq(Role r, Role s){ return lookup(key).getData(); abstract boolean isEmpty(); } public static void init() { if (r == null || s == null){ } public abstract Object get(int i); return null; pwds = new SimpleArrayList(); return false; return null; public abstract List removePersistent(int i); } pwds.add(new PwdTableEntry("Bond",} "007", Role.SUPER_SPY)); } public abstract void set(int i, Object o); } pwds.add(new PwdTableEntry("M", "0", Role.SPY)); } public abstract Object head() throws NoSuchElementException; class DbEntry{ pwds.add(new PwdTableEntry("Q", "1337",if (s == Role.TECH_GUY SUPER_SPY) { )); class DbEntry{ public abstract List tail() throws NoSuchElementException; private String key; } return true; private String key; } private Role reader; } private Role reader; private String data; public static Role doLogin (String userName, String pwd){ private String data; if (r == MOLE) { private static class Nil extends List { public DbEntry(String key, Role reader,for(int String i=0; data){ i < pwds.size(); i++){ return true; public DbEntry(String key, Role reader, String data){ private Nil(){}; this.key = key; if (pwds.get(i) instanceof PwdTableEntry)} { this.key = key; public int size() { return 0; } this.reader = reader; PwdTableEntry e = (PwdTableEntry) pwds.get(i); this.reader = reader; public boolean isEmpty() { return true; } this.data = data; if( e.uname.equals(userName) &&return e.pwd.equals(pwd) (s == r); ){ this.data = data; public Object get(int i) { throw new IllegalArgumentException(); } } return e.role; } } public List removePersistent(int i) { } throw new IllegalArgumentException(); } public String getKey(){ return this.key; } } } public String getKey(){ return this.key; } public Role getReader(){ return this.reader;} } import java.util.Iterator; public Role getReader(){ return this.reader; } public void set(int i, Object o) { throw new IllegalArgumentException(); public String getData(){ return this.data;return } null; import java.util.NoSuchElementException; public String getData(){ return this.data; } } } } } class Login { public class SimpleArrayList implements Iterable { class Login { public Object head() throws NoSuchElementException { } throw new NoSuchElementException(); private static class PwdTableEntry{ class Role { List contents; private static class PwdTableEntry{ } String uname; String uname; public static final Role SPY = new Role("spy");SimpleArrayList() {this.contents = new Nil();}
19/24 p2 query 7→ if (p2 query ok[0]) then Reveal(p2 query ok[1+], p2 hit p1?[0+], p1 hit p2?[0+])
Computer (p2) player’s queries only depend on public data.
Sample policy: Battleship
private PwdTableEntry(String uname,public String static pwd, final Role Role role){ MOLE = new Role("mole"); return lookup(key).getReader(); this.uname=uname; public static final Role TECH_GUY = new Role("tech"); return lookup(key).getReader(); int size() { return contents.size(); } } this.pwd=pwd; } boolean isEmpty() {return contents.isEmpty(); } return null; this.role=role; private final String id; return null; void clear() { this.contents = new Nil(); } } } private Role(String id){ } } this.id = id; private static abstract class List { public String secretOf(String key) { } public String secretOf(String key) { private List() { } if (lookup(key) != null) { private static SimpleArrayList pwds; if (lookup(key) != null) { abstract int size(); return lookup(key).getData(); public static boolean lteq(Role r, Role s){ return lookup(key).getData(); abstract boolean isEmpty(); } public static void init() { if (r == null || s == null){ } public abstract Object get(int i); return null; pwds = new SimpleArrayList(); return false; return null; public abstract List removePersistent(int i); } pwds.add(new PwdTableEntry("Bond",} "007", Role.SUPER_SPY)); } public abstract void set(int i, Object o); } pwds.add(new PwdTableEntry("M", "0", Role.SPY)); } public abstract Object head() throws NoSuchElementException; class DbEntry{ pwds.add(new PwdTableEntry("Q", "1337",if (s == Role.TECH_GUY SUPER_SPY) { )); class DbEntry{ public abstract List tail() throws NoSuchElementException; private String key; } return true; private String key; } private Role reader; } private Role reader; private String data; public static Role doLogin (String userName, String pwd){ Computer private String data; if (r == MOLE) { private static class Nil extends List { public DbEntry(String key, Role reader,for(int String i=0; data){ i < pwds.size(); i++){ return true; public DbEntry(String key, Role reader, String data){ private Nil(){}; this.key = key; if (pwds.get(i) instanceof PwdTableEntry)} { player, p2 this.key = key; public int size() { return 0; } this.reader = reader; PwdTableEntry e = (PwdTableEntry) pwds.get(i); this.reader = reader; public boolean isEmpty() { return true; } this.data = data; if( e.uname.equals(userName) &&return e.pwd.equals(pwd) (s == r); ){ this.data = data; public Object get(int i) { throw new IllegalArgumentException(); } } Human return e.role; } } public List removePersistent(int i) { } throw new IllegalArgumentException(); } public String getKey(){ return this.key; } } } public String getKey(){ return this.key; } public Roleplayer, getReader(){ return p1 this.reader;} } import java.util.Iterator; public Role getReader(){ return this.reader; } public void set(int i, Object o) { throw new IllegalArgumentException(); public String getData(){ return this.data;return } null; import java.util.NoSuchElementException; public String getData(){ return this.data; } @input "p1 board" } } } } class Login { public class SimpleArrayList implements Iterable { class Login { public Object head() throws NoSuchElementException { } throw new NoSuchElementException(); private static class PwdTableEntry{ class Role { List contents; private static class PwdTableEntry{ } String uname; String uname; public static final Role SPY = new Role("spy");SimpleArrayList() {this.contents = new Nil();}
19/24 Sample policy: Battleship
private PwdTableEntry(String uname,public String static pwd, final Role Role role){ MOLE = new Role("mole"); return lookup(key).getReader(); this.uname=uname; public static final Role TECH_GUY = new Role("tech"); return lookup(key).getReader(); int size() { return contents.size(); } } this.pwd=pwd; } boolean isEmpty() {return contents.isEmpty(); } return null; this.role=role; private final String id; return null; void clear() { this.contents = new Nil(); } } } private Role(String id){ } } this.id = id; private static abstract class List { public String secretOf(String key) { } public String secretOf(String key) { private List() { } if (lookup(key) != null) { private static SimpleArrayList pwds; if (lookup(key) != null) { abstract int size(); return lookup(key).getData(); public static boolean lteq(Role r, Role s){ return lookup(key).getData(); abstract boolean isEmpty(); } public static void init() { if (r == null || s == null){ } public abstract Object get(int i); return null; pwds = new SimpleArrayList(); return false; return null; public abstract List removePersistent(int i); } pwds.add(new PwdTableEntry("Bond",} "007", Role.SUPER_SPY)); } public abstract void set(int i, Object o); } pwds.add(new PwdTableEntry("M", "0", Role.SPY)); } public abstract Object head() throws NoSuchElementException; class DbEntry{ pwds.add(new PwdTableEntry("Q", "1337",if (s == Role.TECH_GUY SUPER_SPY) { )); class DbEntry{ public abstract List tail() throws NoSuchElementException; private String key; } return true; private String key; } private Role reader; } private Role reader; private String data; public static Role doLogin (String userName, String pwd){ Computer private String data; if (r == MOLE) { private static class Nil extends List { public DbEntry(String key, Role reader,for(int String i=0; data){ i < pwds.size(); i++){ return true; public DbEntry(String key, Role reader, String data){ private Nil(){}; this.key = key; if (pwds.get(i) instanceof PwdTableEntry)} { player, p2 this.key = key; public int size() { return 0; } this.reader = reader; PwdTableEntry e = (PwdTableEntry) pwds.get(i); this.reader = reader; public boolean isEmpty() { return true; } this.data = data; if( e.uname.equals(userName) &&return e.pwd.equals(pwd) (s == r); ){ this.data = data; public Object get(int i) { throw new IllegalArgumentException(); } } Human return e.role; } } public List removePersistent(int i) { } throw new IllegalArgumentException(); } public String getKey(){ return this.key; } } } public String getKey(){ return this.key; } public Roleplayer, getReader(){ return p1 this.reader;} } import java.util.Iterator; public Role getReader(){ return this.reader; } public void set(int i, Object o) { throw new IllegalArgumentException(); public String getData(){ return this.data;return } null; import java.util.NoSuchElementException; public String getData(){ return this.data; } @input "p1 board" } } } } class Login { public class SimpleArrayList implements Iterable { class Login { public Object head() throws NoSuchElementException { } throw new NoSuchElementException(); private static class PwdTableEntry{ class Role { List contents; private static class PwdTableEntry{ } String uname; String uname; public static final Role SPY = new Role("spy");SimpleArrayList() {this.contents = new Nil();}
p2 query 7→ if (p2 query ok[0]) then Reveal(p2 query ok[1+], p2 hit p1?[0+], p1 hit p2?[0+])
Computer (p2) player’s queries only depend on public data.19/24 Sample policy: Computer psychiatrist
display 7→ if-executed (Liz.sanitize(java.lang.String)) then Reveal(input[0], input[1+])
Inputs are not displayed unless sanitize has been called.
20/24 The prototype scales to low 1000s loc, but is not performance tuned
!"##$%
01#23$456)748#)9:;)<46#:)5=)>5?#
/++
.++
A -++ : ? 6 5
2 *++ # : @ ) #
8 ,++ 4 7 %++
+ %+ %++ %+++ %++++ <46#:)5=)25?#
C665$'$456:)9:;)<46#:)5=)>5?# 21/24 ,+ %B %/ : 6 5 4 %- $ ' $
5 %, 6 6
C %+ ) D # B 8 8
' / D ( 5
D - & , + %++ %+++ %++++ <46#:)5=)25?#
I6=#D#62#)C665$'$456:)9:;)JIK)7LG#)C665$'$456: &'(#)*
%++++
%+++
: C665$'$456: 6 5 4 $ %++ J4=)C665$'$456: ' $ 5 6 6 C %+
% E'$$F#:"4G &5H#D !"##$%
01#23$456)748#)9:;)<46#:)5=)>5?#
/++
.++
A -++ : ? 6 5
2 *++ # : @ ) #
8 ,++ 4 7 %++
We succeeded+ in requiring few %+ %++ %+++ %++++ programmer annotations<46#:)5=)25?#
C665$'$456:)9:;)<46#:)5=)>5?#
,+ %B %/ : 6 5 4 %- $ ' $
5 %, 6 6
C %+ ) D # B 8 8
' / D ( 5
D - & , + %++ %+++ %++++ <46#:)5=)25?#
22/24
I6=#D#62#)C665$'$456:)9:;)JIK)7LG#)C665$'$456: &'(#)*
%++++
%+++
: C665$'$456: 6 5 4 $ %++ J4=)C665$'$456: ' $ 5 6 6 C %+
% E'$$F#:"4G &5H#D Conclusion
23/24 Policy inference via dataflow is a promising info. flow analysis
This project demonstrates:
A novel workflow of iterative policy refinement via inference Expressive policies that explain information flows and reflect program structure A precise analysis suitable for (mostly) unmodified Java programs
24/24 Bonus Slides Policies express how information flows from inputs to outputs
where
what
when
[Sabelfeld & Sands ’05] NB. Our policies generalize delimited release [Askarov & Sabelfeld ’07] Annotation burden compares well with more explicit systems
Jif primary goals: modular typing, DLM policies, and not inference. [Myers, Zheng, Zdancewic, Chong, Nystrom ’01–’09] Annotation burden compares well with more explicit systems
!"##$%
456#2#57#)8550$'$.05-)9-:);4<)=>/#)8550$'$.05-
%3333
%333
- 8550$'$.05- 5 0 . $ %33 ;.6)8550$'$.05- ' $ 0 5 5 8 %3
% +'$$,#-"./ &01#2
Jif primary goals: modular typing, DLM policies, and not inference. [Myers, Zheng, Zdancewic, Chong, Nystrom ’01–’09]
&'(#)* Goal: Policies that explain and reflect information flows
Inferred policy
out 7→ if (authCheckOk[0]) then Reveal(secret[0+], authCheckOk[1+])
Policies...... reflect structure of information flow within program . . . describe flow in terms of meaningful channel names Policy rewriting is needed for widening and improves readability
Example
Reveal(H[j],H[i+]) = Reveal[i+] (provided i ≤ j) Reveal(H[j],H[i+]) v Reveal(H[min(i, j)+]) v Reveal(H[0+])
Widening ∇(p1, p2): Let p := p1 and p2 If |p| ≤ threshold return p Rewrite (=) until |p| ≤ threshold or no further rewrites possible Rewrite conservatively (v) until |p| ≤ threshold Result := p