Information Flow Analysis via Path Condition Refinement

Similar documents
3-Valued Abstraction-Refinement

Software Verification using Predicate Abstraction and Iterative Refinement: Part 1

Predicate Abstraction: A Tutorial

Abstractions and Decision Procedures for Effective Software Model Checking

Hoare Logic I. Introduction to Deductive Program Verification. Simple Imperative Programming Language. Hoare Logic. Meaning of Hoare Triples

Scalable and Accurate Verification of Data Flow Systems. Cesare Tinelli The University of Iowa

Lecture 2: Symbolic Model Checking With SAT

Model Checking: An Introduction

Software Verification with Abstraction-Based Methods

Model Checking, Theorem Proving, and Abstract Interpretation: The Convergence of Formal Verification Technologies

Algorithmic verification

SMT BASICS WS 2017/2018 ( ) LOGIC SATISFIABILITY MODULO THEORIES. Institute for Formal Models and Verification Johannes Kepler Universität Linz

Solving SAT Modulo Theories

Formal Verification Techniques. Riccardo Sisto, Politecnico di Torino

Double Header. Model Checking. Model Checking. Overarching Plan. Take-Home Message. Spoiler Space. Topic: (Generic) Model Checking

Static Program Analysis

EFFICIENT PREDICATE ABSTRACTION OF PROGRAM SUMMARIES

Counterexample-Guided Abstraction Refinement

Automata-Theoretic Model Checking of Reactive Systems

Practical SAT Solving

SAT-based Model Checking: Interpolation, IC3, and Beyond

Quantum Computing Approach to V&V of Complex Systems Overview

Interpolation. Seminar Slides. Betim Musa. 27 th June Albert-Ludwigs-Universität Freiburg

Information Flow Inference for ML

Stability and Stabilization of polynomial dynamical systems. Hadi Ravanbakhsh Sriram Sankaranarayanan University of Colorado, Boulder

Automated Program Verification and Testing 15414/15614 Fall 2016 Lecture 8: Procedures for First-Order Theories, Part 2

Tutorial 1: Modern SMT Solvers and Verification

PROPOSITIONAL LOGIC. VL Logik: WS 2018/19

Property Directed Equivalence via Abstract Simulation. Grigory Fedyukovich, Arie Gurfinkel, and Natasha Sharygina

Deductive Verification

The Eager Approach to SMT. Eager Approach to SMT

CEGAR:Counterexample-Guided Abstraction Refinement

Axiomatic Semantics: Verification Conditions. Review of Soundness of Axiomatic Semantics. Questions? Announcements

or simply: IC3 A Simplified Description

Towards Lightweight Integration of SMT Solvers

Axiomatic Semantics: Verification Conditions. Review of Soundness and Completeness of Axiomatic Semantics. Announcements

Automatic Generation of Polynomial Invariants for System Verification

The Software Model Checker BLAST

Vinter: A Vampire-Based Tool for Interpolation

Equalities and Uninterpreted Functions. Chapter 3. Decision Procedures. An Algorithmic Point of View. Revision 1.0

Decision Procedures. Jochen Hoenicke. Software Engineering Albert-Ludwigs-University Freiburg. Winter Term 2016/17

Proving Unsatisfiability in Non-linear Arithmetic by Duality

Predicate Abstraction and Refinement for Verifying Multi-Threaded Programs

Constraint Solving for Program Verification: Theory and Practice by Example

FMCAD 2013 Parameter Synthesis with IC3

Bounded Model Checking with SAT/SMT. Edmund M. Clarke School of Computer Science Carnegie Mellon University 1/39

Static Program Analysis using Abstract Interpretation

Ranked Predicate Abstraction for Branching Time. Complete, Incremental, and Precise

First-Order Logic First-Order Theories. Roopsha Samanta. Partly based on slides by Aaron Bradley and Isil Dillig

Algorithmic Verification of Stability of Hybrid Systems

Propositional and Predicate Logic - V

Symbolic Trajectory Evaluation (STE): Orna Grumberg Technion, Israel

On the Probabilistic Symbolic Analysis of Software. Corina Pasareanu CMU-SV NASA Ames

Reasoning About Imperative Programs. COS 441 Slides 10b

Nested Interpolants. Matthias Heizmann Jochen Hoenicke Andreas Podelski POPL University of Freiburg, Germany

Constraint Solving for Finite Model Finding in SMT Solvers

SAT-Based Verification with IC3: Foundations and Demands

Lecture Notes: Axiomatic Semantics and Hoare-style Verification

IC3 and Beyond: Incremental, Inductive Verification

Axiomatic Semantics. Lecture 9 CS 565 2/12/08

LOGIC PROPOSITIONAL REASONING

Simply Typed Lambda Calculus

An Introduction to Z3

Lecture 13: Soundness, Completeness and Compactness

1 Algebraic Methods. 1.1 Gröbner Bases Applied to SAT

Nonlinear Control as Program Synthesis (A Starter)

Automated Circular Assume-Guarantee Reasoning with N-way Decomposition and Alphabet Refinement

Automatic Verification of Parameterized Data Structures

Proofs of Correctness: Introduction to Axiomatic Verification

The State Explosion Problem

Notes. Corneliu Popeea. May 3, 2013

Foundations of Lazy SMT and DPLL(T)

The Reachability-Bound Problem. Gulwani and Zuleger PLDI 10

Reasoning about State Constraints in the Situation Calculus

Softwaretechnik. Lecture 13: Design by Contract. Peter Thiemann University of Freiburg, Germany

Rewriting for Satisfiability Modulo Theories

Information Flow Inference for ML

Model Checking via Automatic Abstraction

Exploiting resolution proofs to speed up LTL vacuity detection for BMC

EECS 144/244: Fundamental Algorithms for System Modeling, Analysis, and Optimization

First-order resolution for CTL

Practical SAT Solving

The TLA + proof system

Design of Distributed Systems Melinda Tóth, Zoltán Horváth

Lecture Notes on Software Model Checking

Satisfiability Modulo Theories (SMT)

Understanding IC3. Aaron R. Bradley. ECEE, CU Boulder & Summit Middle School. Understanding IC3 1/55

Simplifying Loop Invariant Generation Using Splitter Predicates

Model Checking & Program Analysis

SAT-Solving: From Davis- Putnam to Zchaff and Beyond Day 3: Recent Developments. Lintao Zhang

Simplifying Loop Invariant Generation Using Splitter Predicates

Hoare Logic: Reasoning About Imperative Programs

The Polyranking Principle

Quantifiers. Leonardo de Moura Microsoft Research

Semantic Equivalences and the. Verification of Infinite-State Systems 1 c 2004 Richard Mayr

Ivy: Safety Verification by Interactive Generalization

A Little Logic. Propositional Logic. Satisfiability Problems. Solving Sudokus. First Order Logic. Logic Programming

Softwaretechnik. Lecture 13: Design by Contract. Peter Thiemann University of Freiburg, Germany

Bilateral Proofs of Safety and Progress Properties of Concurrent Programs (Working Draft)

Binary Decision Diagrams and Symbolic Model Checking

Transcription:

Information Flow Analysis via Path Condition Refinement Mana Taghdiri, Gregor Snelting, Carsten Sinz Karlsruhe Institute of Technology, Germany FAST September 16, 2010 KIT University of the State of Baden-Wuerttemberg and National Research Center of the Helmholtz Association www.kit.edu

Problem statement Information Flow Control (IFC) Looks for a flow between two points in a program Analyzes program s source code Either discovers a potential (illegal) flow or guarantees that no flow is possible Problem Sound IFC methods produce false alarms False alarms have devastating effects on practicability Our goal To improve precision while maintaining soundness 2 9/15/10

PDG-based IFC Program dependence graph (PDG) Nodes represent program statements Edges give data-dependency Statement s is data-dependent on statement t iff s uses a variable assigned in t Edges give control-dependency Statement s is control-dependent on statement t iff s is executed only if an expression in t has a specific value PDG can be used for information flow problem Information flow is possible only if there is a PDG path b/w the points Flow-sensitive, context-sensitive, object-sensitive Fewer false alarms, but more expensive than security type systems 3 9/15/10

Example PDG 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a[0] = System.in.read(); 3. a[1] = System.in.read(); 4. a[2] = System.in.read(); 5. assert(a[0] > 0); 6. assert(a[1] > 0); 7. assert(a[2] > 0); 8. int sum = 0; 9. int i = 0; 10. while (i < 3) { 11. if (sum == 0) 12. sum = sum+a[i]; 13. i = i+1; } 14. System.out.println(sum); } main Data dependence Control dependence 1 2 3 4 8 9 10 14 11 13 12 4 9/15/10

Example PDG 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a[0] = System.in.read(); 3. a[1] = System.in.read(); 4. a[2] = System.in.read(); 5. assert(a[0] > 0); 6. assert(a[1] > 0); 7. assert(a[2] > 0); 8. int sum = 0; 9. int i = 0; 10. while (i < 3) { 11. if (sum == 0) 12. sum = sum+a[i]; 13. i = i+1; } 14. System.out.println(sum); } main Data dependence Control dependence 1 2 3 4 8 9 10 14 11 13 12 5 9/15/10

Example PDG 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a[0] = System.in.read(); 3. a[1] = System.in.read(); 4. a[2] = System.in.read(); 5. assert(a[0] > 0); 6. assert(a[1] > 0); 7. assert(a[2] > 0); 8. int sum = 0; 9. int i = 0; 10. while (i < 3) { 11. if (sum == 0) 12. sum = sum+a[i]; 13. i = i+1; } 14. System.out.println(sum); } main Data dependence Control dependence 1 2 3 4 8 9 10 14 11 13 12 6 9/15/10

Example PDG-based IFC 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a[0] = System.in.read(); // PUBLIC 3. a[1] = System.in.read(); // SECRET 4. a[2] = System.in.read(); // SECRET 5. assert(a[0] > 0); 6. assert(a[1] > 0); 7. assert(a[2] > 0); 8. int sum = 0; 9. int i = 0; 10. while (i < 3) { 11. if (sum == 0) 12. sum = sum+a[i]; 13. i = i+1; } 14. System.out.println(sum); } Is there a flow from a[1] to sum? 7 9/15/10

Example 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a[0] = System.in.read(); 3. a[1] = System.in.read(); 4. a[2] = System.in.read(); 5. assert(a[0] > 0); 6. assert(a[1] > 0); 7. assert(a[2] > 0); 8. int sum = 0; 9. int i = 0; 10. while (i < 3) { 11. if (sum == 0) 12. sum = sum+a[i]; 13. i = i+1; } Is there a flow from a[1] to sum? 14. System.out.println(sum); } YES!, but this is just a false alarm main 1 2 3 4 8 9 10 14 11 13 12 8 9/15/10

PC-based IFC Path conditions (PC) are built on top of PDG A flow is possible only along PDG paths Characterizes the conditions over program variables that must be satisfied for a path to be taken Example: 1. a[i+3] = x; 2. if (i>10 && j<5) 3. y = a[2*j-42]; PDG cotains a path 1 3 PC(1, 3) (i > 10) (j < 5) (i + 3 = 2j 42) false So flow is impossible 9 9/15/10

PC-based IFC Path conditions are more precise than PDG alone If a path condition PC(x, y) is not satisfiable, it is guaranteed that there is no flow from x to y, even if the PDG contains a path x y Solving a path condition produces a witness for flow Variables in PC are existentially quantified A constraint solver can find a solution A solution satisfying PC provides values for program inputs PDG gives only a binary answer: either a flow is possible, or no flow exists But path conditions may also produce false alarms Due to conservative abstractions 10 9/15/10

Example SSA form 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a 1 [0] = System.in.read(); 3. a 2 [1] = System.in.read(); 4. a 3 [2] = System.in.read(); 5. assert(a 3 [0] > 0); 6. assert(a 3 [1] > 0); 7. assert(a 3 [2] > 0); 8. int sum 1 = 0; 9. int i 1 = 0; 10. while [i 2 = ϕ(i 1, i 3 ); sum 2 = ϕ(sum 1, sum 4 )] (i 2 < 3) { 11. if (sum 2 == 0) 12. sum 3 = sum 2 +a 3 [i 2 ]; 13. [sum 4 = ϕ(sum 2, sum 3 )] i 3 = i 2 +1; } 14. System.out.println(sum 2 ); } Is there a flow from a[1] to sum? main 1 2 3 4 8 9 10 14 11 13 12 11 9/15/10

Example path condition 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a 1 [0] = System.in.read(); 3. a 2 [1] = System.in.read(); 4. a 3 [2] = System.in.read(); 5. assert(a 3 [0] > 0); 6. assert(a 3 [1] > 0); 7. assert(a 3 [2] > 0); 8. int sum 1 = 0; 9. int i 1 = 0; 10. while [i 2 = ϕ(i 1, i 3 ); sum 2 = ϕ(sum 1, sum 4 )] (i 2 < 3) { 11. if (sum 2 == 0) 12. sum 3 = sum 2 +a 3 [i 2 ]; 13. [sum 4 = ϕ(sum 2, sum 3 )] i 3 = i 2 +1; } 14. System.out.println(sum 2 ); } Is there a flow from a[1] to sum? main 1 2 3 4 8 9 10 14 11 13 12 PC (3, 14) (i 2 = 1) 12 9/15/10

Example path condition 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a 1 [0] = System.in.read(); 3. a 2 [1] = System.in.read(); 4. a 3 [2] = System.in.read(); 5. assert(a 3 [0] > 0); 6. assert(a 3 [1] > 0); 7. assert(a 3 [2] > 0); 8. int sum 1 = 0; 9. int i 1 = 0; 10. while [i 2 = ϕ(i 1, i 3 ); sum 2 = ϕ(sum 1, sum 4 )] (i 2 < 3) { 11. if (sum 2 == 0) 12. sum 3 = sum 2 +a 3 [i 2 ]; 13. [sum 4 = ϕ(sum 2, sum 3 )] i 3 = i 2 +1; } 14. System.out.println(sum 2 ); } Is there a flow from a[1] to sum? main 1 2 3 4 8 9 10 14 11 13 PC (3, 14) (sum 2 = sum 3 ) 12 13 9/15/10

Example path condition 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a 1 [0] = System.in.read(); 3. a 2 [1] = System.in.read(); 4. a 3 [2] = System.in.read(); 5. assert(a 3 [0] > 0); 6. assert(a 3 [1] > 0); 7. assert(a 3 [2] > 0); 8. int sum 1 = 0; 9. int i 1 = 0; 10. while [i 2 = ϕ(i 1, i 3 ); sum 2 = ϕ(sum 1, sum 4 )] (i 2 < 3) { 11. if (sum 2 == 0) 12. sum 3 = sum 2 +a 3 [i 2 ]; 13. [sum 4 = ϕ(sum 2, sum 3 )] i 3 = i 2 +1; } 14. System.out.println(sum 2 ); } Is there a flow from a[1] to sum? main 1 2 3 4 8 9 10 14 11 13 12 PC (3, 14) (sum 2 = 0) 14 9/15/10

Example path condition 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a 1 [0] = System.in.read(); 3. a 2 [1] = System.in.read(); 4. a 3 [2] = System.in.read(); 5. assert(a 3 [0] > 0); 6. assert(a 3 [1] > 0); 7. assert(a 3 [2] > 0); 8. int sum 1 = 0; 9. int i 1 = 0; 10. while [i 2 = ϕ(i 1, i 3 ); sum 2 = ϕ(sum 1, sum 4 )] (i 2 < 3) { 11. if (sum 2 == 0) 12. sum 3 = sum 2 +a 3 [i 2 ]; 13. [sum 4 = ϕ(sum 2, sum 3 )] i 3 = i 2 +1; } 14. System.out.println(sum 2 ); } Is there a flow from a[1] to sum? PC (3, 14) (sum 1 = 0) (i 1 = 0) (i 2 = 1) (sum 2 = sum 3 ) (i 2 < 3) (sum 2 = 0) (a 3 [0] > 0) (a 3 [1] > 0) (a 3 [2] > 0) (i 2 = i 1 i 2 = i 3 ) (sum 2 = sum 1 sum 2 = sum 4 ) (sum 4 = sum 2 sum 4 = sum 3 ) Satisfying solution (potential witness): a[0] = 15, a[1] = 5, a[2] = 42, i 1 = 0, i 2 = i 3 = 1, sum 1 = sum 2 = sum 3 = sum 4 = 0 But, this is a false alarm 15 9/15/10

False alarms in PC Path conditions are Flow-sensitive Context-sensitive Object-sensitive But yet, may produce false alarms To preserve soundness, path conditions make conservative abstractions Cannot distinguish between different iterations of a loop Static analysis alone cannot analyze loops precisely 16 9/15/10

CEGAR-based IFC Counterexample-guided abstraction refinement (CEGAR) Increases precision while preserving scalability Successfully used in software model checking and data structure analysis, but never for IFC Follows a fully automatic solve-validate-refine loop Goal: Generate a flow whose execution truly demonstrates the security breach Reduce the number of false alarms Approach: Keep looking for better witnesses until existence of the flow is established or refuted Make path conditions more precise iteratively as needed 17 9/15/10

CEGAR incremental analysis Program behavior Contains a flow? 18 9/15/10

CEGAR incremental analysis Abstract behavior Program behavior Contains a flow? 19 9/15/10

CEGAR incremental analysis Abstract behavior Program behavior Contains a flow? NO! 20 9/15/10

CEGAR incremental analysis Abstract behavior Program behavior Contains a flow? NO! Yes 21 9/15/10

CEGAR incremental analysis Abstract behavior Program behavior Contains a flow? 22 9/15/10

CEGAR incremental analysis Abstract behavior Program behavior Contains a flow? NO! 23 9/15/10

CEGAR incremental analysis Abstract behavior Program behavior Contains a flow? NO! Yes 24 9/15/10

CEGAR-based IFC Initial path condition is an over-approximation of conditions necessary for flow program Generate PC path condition Solve PC No flow! new path condition potential witness Refine PC false witness Check Witness Real witness! 25 9/15/10

CEGAR-based IFC We use an off-the-shelf SMT (SAT Modulo Theory) solver to check path conditions The solver is complete: if a solution exists, it is guaranteed to find it The solver returns only one solution at a time Path conditions are sound: if they are unsatisfiable, it is guaranteed that no flow exists program Generate PC path condition Solve PC No flow! new path condition potential witness Refine PC false witness Check Witness Real witness! 26 9/15/10

CEGAR-based IFC A solution to PC represents a potential witness for information flow A solution is checked for validity by running the program on the inputs given by the solution The execution is monitored and compared to the solution A contradictory program state denotes that the witness is spurious program Generate PC path condition Solve PC No flow! new path condition potential witness Refine PC false witness Check Witness Real witness! 27 9/15/10

Example potential witness 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a 1 [0] = System.in.read(); 3. a 2 [1] = System.in.read(); 4. a 3 [2] = System.in.read(); 5. assert(a 3 [0] > 0); 6. assert(a 3 [1] > 0); 7. assert(a 3 [2] > 0); 8. int sum 1 = 0; 9. int i 1 = 0; 10. while [i 2 = ϕ(i 1, i 3 ); sum 2 = ϕ(sum 1, sum 4 )] (i 2 < 3) { 11. if (sum 2 == 0) 12. sum 3 = sum 2 +a 3 [i 2 ]; 13. [sum 4 = ϕ(sum 2, sum 3 )] i 3 = i 2 +1; } 14. System.out.println(sum 2 ); } Is there a flow from a[1] to sum? Initial PC solution (potential witness): a[0] = 15, a[1] = 5, a[2] = 42, i 1 = 0, i 2 = i 3 = 1, sum 1 = sum 2 = sum 3 = sum 4 = 0 28 9/15/10

Example program execution 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a 1 [0] = System.in.read(); 3. a 2 [1] = System.in.read(); 4. a 3 [2] = System.in.read(); 5. assert(a 3 [0] > 0); 6. assert(a 3 [1] > 0); 7. assert(a 3 [2] > 0); 8. int sum 1 = 0; 9. int i 1 = 0; 10. while [i 2 = ϕ(i 1, i 3 ); sum 2 = ϕ(sum 1, sum 4 )] (i 2 < 3) { 11. if (sum 2 == 0) 12. sum 3 = sum 2 +a 3 [i 2 ]; 13. [sum 4 = ϕ(sum 2, sum 3 )] i 3 = i 2 +1; } 14. System.out.println(sum 2 ); } [a[0] = 15] [.., a[1] = 5] [.., a[2] = 42] potential witness: a[0] = 15, a[1] = 5, a[2] = 42, i 1 = 0, i 2 = i 3 = 1, sum 1 = sum 2 = sum 3 = sum 4 = 0 29 9/15/10

Example program execution 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a 1 [0] = System.in.read(); 3. a 2 [1] = System.in.read(); 4. a 3 [2] = System.in.read(); 5. assert(a 3 [0] > 0); 6. assert(a 3 [1] > 0); 7. assert(a 3 [2] > 0); 8. int sum 1 = 0; 9. int i 1 = 0; 10. while [i 2 = ϕ(i 1, i 3 ); sum 2 = ϕ(sum 1, sum 4 )] (i 2 < 3) { 11. if (sum 2 == 0) 12. sum 3 = sum 2 +a 3 [i 2 ]; 13. [sum 4 = ϕ(sum 2, sum 3 )] i 3 = i 2 +1; } 14. System.out.println(sum 2 ); } [a[0] = 15] [.., a[1] = 5] [.., a[2] = 42] [.., sum 1 = 0] [.., i 1 = 0] potential witness: a[0] = 15, a[1] = 5, a[2] = 42, i 1 = 0, i 2 = i 3 = 1, sum 1 = sum 2 = sum 3 = sum 4 = 0 30 9/15/10

Example program execution 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a 1 [0] = System.in.read(); 3. a 2 [1] = System.in.read(); 4. a 3 [2] = System.in.read(); 5. assert(a 3 [0] > 0); 6. assert(a 3 [1] > 0); 7. assert(a 3 [2] > 0); 8. int sum 1 = 0; 9. int i 1 = 0; 10. while [i 2 = ϕ(i 1, i 3 ); sum 2 = ϕ(sum 1, sum 4 )] (i 2 < 3) { 11. if (sum 2 == 0) 12. sum 3 = sum 2 +a 3 [i 2 ]; 13. [sum 4 = ϕ(sum 2, sum 3 )] i 3 = i 2 +1; } 14. System.out.println(sum 2 ); } [a[0] = 15] [.., a[1] = 5] [.., a[2] = 42] [.., sum 1 = 0] [.., i 1 = 0] potential witness: a[0] = 15, a[1] = 5, a[2] = 42, i 1 = 0, i 2 = i 3 = 1, sum 1 = sum 2 = sum 3 = sum 4 = 0 [.., sum 2 = 0, i 2 = 0] 31 9/15/10

Example program execution 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a 1 [0] = System.in.read(); 3. a 2 [1] = System.in.read(); 4. a 3 [2] = System.in.read(); 5. assert(a 3 [0] > 0); 6. assert(a 3 [1] > 0); 7. assert(a 3 [2] > 0); 8. int sum 1 = 0; 9. int i 1 = 0; 10. while [i 2 = ϕ(i 1, i 3 ); sum 2 = ϕ(sum 1, sum 4 )] (i 2 < 3) { 11. if (sum 2 == 0) 12. sum 3 = sum 2 +a 3 [i 2 ]; 13. [sum 4 = ϕ(sum 2, sum 3 )] i 3 = i 2 +1; } 14. System.out.println(sum 2 ); } [a[0] = 15] [.., a[1] = 5] [.., a[2] = 42] [.., sum 1 = 0] [.., i 1 = 0] potential witness: a[0] = 15, a[1] = 5, a[2] = 42, i 1 = 0, i 2 = i 3 = 1, sum 1 = sum 2 = sum 3 = sum 4 = 0 [.., sum 2 = 0, i 2 = 0] [.., sum 3 = 15] [.., i 3 = 1] 32 9/15/10

Example program execution 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a 1 [0] = System.in.read(); 3. a 2 [1] = System.in.read(); 4. a 3 [2] = System.in.read(); 5. assert(a 3 [0] > 0); 6. assert(a 3 [1] > 0); 7. assert(a 3 [2] > 0); 8. int sum 1 = 0; 9. int i 1 = 0; 10. while [i 2 = ϕ(i 1, i 3 ); sum 2 = ϕ(sum 1, sum 4 )] (i 2 < 3) { 11. if (sum 2 == 0) 12. sum 3 = sum 2 +a 3 [i 2 ]; 13. [sum 4 = ϕ(sum 2, sum 3 )] i 3 = i 2 +1; } 14. System.out.println(sum 2 ); } [a[0] = 15] [.., a[1] = 5] [.., a[2] = 42] [.., sum 1 = 0] [.., i 1 = 0] potential witness: a[0] = 15, a[1] = 5, a[2] = 42, i 1 = 0, i 2 = i 3 = 1, sum 1 = sum 2 = sum 3 = sum 4 = 0 [.., sum 2 = 15, i 2 = 1] [.., sum 3 = 15] [.., i 3 = 2] 33 9/15/10

Example program execution 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a 1 [0] = System.in.read(); 3. a 2 [1] = System.in.read(); 4. a 3 [2] = System.in.read(); 5. assert(a 3 [0] > 0); 6. assert(a 3 [1] > 0); 7. assert(a 3 [2] > 0); 8. int sum 1 = 0; 9. int i 1 = 0; 10. while [i 2 = ϕ(i 1, i 3 ); sum 2 = ϕ(sum 1, sum 4 )] (i 2 < 3) { 11. if (sum 2 == 0) 12. sum 3 = sum 2 +a 3 [i 2 ]; 13. [sum 4 = ϕ(sum 2, sum 3 )] i 3 = i 2 +1; } 14. System.out.println(sum 2 ); } [a[0] = 15] [.., a[1] = 5] [.., a[2] = 42] [.., sum 1 = 0] [.., i 1 = 0] potential witness: a[0] = 15, a[1] = 5, a[2] = 42, i 1 = 0, i 2 = i 3 = 1, sum 1 = sum 2 = sum 3 = sum 4 = 0 [.., sum 2 = 15, i 2 = 2] [.., sum 3 = 15] [.., i 3 = 3] 34 9/15/10

Example program execution 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a 1 [0] = System.in.read(); 3. a 2 [1] = System.in.read(); 4. a 3 [2] = System.in.read(); 5. assert(a 3 [0] > 0); 6. assert(a 3 [1] > 0); 7. assert(a 3 [2] > 0); 8. int sum 1 = 0; 9. int i 1 = 0; 10. while [i 2 = ϕ(i 1, i 3 ); sum 2 = ϕ(sum 1, sum 4 )] (i 2 < 3) { 11. if (sum 2 == 0) 12. sum 3 = sum 2 +a 3 [i 2 ]; 13. [sum 4 = ϕ(sum 2, sum 3 )] i 3 = i 2 +1; } 14. System.out.println(sum 2 ); } [a[0] = 15] [.., a[1] = 5] [.., a[2] = 42] [.., sum 1 = 0] [.., i 1 = 0] potential witness: a[0] = 15, a[1] = 5, a[2] = 42, i 1 = 0, i 2 = i 3 = 1, sum 1 = sum 2 = sum 3 = sum 4 = 0 [.., sum 2 = 15, i 2 = 3] [.., sum 3 = 15] [.., i 3 = 3] 35 9/15/10

Example program execution contradiction 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a 1 [0] = System.in.read(); 3. a 2 [1] = System.in.read(); 4. a 3 [2] = System.in.read(); 5. assert(a 3 [0] > 0); 6. assert(a 3 [1] > 0); 7. assert(a 3 [2] > 0); 8. int sum 1 = 0; 9. int i 1 = 0; 10. while [i 2 = ϕ(i 1, i 3 ); sum 2 = ϕ(sum 1, sum 4 )] (i 2 < 3) { 11. if (sum 2 == 0) 12. sum 3 = sum 2 +a 3 [i 2 ]; 13. [sum 4 = ϕ(sum 2, sum 3 )] i 3 = i 2 +1; } 14. System.out.println(sum 2 ); } [a[0] = 15] [.., a[1] = 5] [.., a[2] = 42] [.., sum 1 = 0] [.., i 1 = 0] potential witness: a[0] = 15, a[1] = 5, a[2] = 42, i 1 = 0, i 2 = i 3 = 1, sum 1 = sum 2 = sum 3 = sum 4 = 0 [.., sum 3 = 15] [.., i 3 = 3] This witness is spurious!! [.., sum 2 = 0, i 2 = 0] [.., sum 2 = 15, i 2 = 1] [.., sum 2 = 15, i 2 = 2] [.., sum 2 = 15, i 2 = 3] 36 9/15/10

CEGAR-based IFC To refine the path condition, run the code symbolically, following the previous concrete execution of the previous stage During the symbolic execution, compute symbolic values of variables Also compute the symbolic control conditions taken in this path (guards) program Generate PC path condition Solve PC No flow! new path condition potential witness Refine PC false witness Check Witness Real witness! 37 9/15/10

CEGAR-based IFC Construct a formula that gives the symbolic values of program variables at the contradictory program point Use the SMT solver again to solve this formula wrt the current witness The witness provides a partial solution for the formula This formula is unsatisfiable program Generate PC path condition Solve PC No flow! new path condition potential witness Refine PC false witness Check Witness Real witness! 38 9/15/10

CEGAR-based IFC Since the SMT solver cannot find a solution, it generates a proof of unsatisfiability Encodes why the current witness is invalid Refined PC = old PC conjoined with the unsatisfiability proof program Generate PC path condition Solve PC No flow! new path condition potential witness Refine PC false witness Check Witness Real witness! 39 9/15/10

Example symbolic execution 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a [0] = System.in.read(); 3. a [1] = System.in.read(); 4. a [2] = System.in.read(); 5. assert(a [0] > 0); 6. assert(a [1] > 0); 7. assert(a [2] > 0); 8. int sum = 0; 9. int i = 0; 10. while (i < 3) { 11. if (sum == 0) 12. sum = sum+a [i]; 13. i = i+1; } 14. System.out.println(sum); } Symbolic values: [a[0] = A0] [.., a[1] = A1] [.., a[2] = A2] [.., sum = 0] [.., i = 0] sum = if guard then 0 else ANY i = if guard then 0 else ANY Symbolic guards: {(A0 > 0)} {.. (A1 > 0)} {.. (A2 > 0)} 40 9/15/10

Example symbolic execution 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a [0] = System.in.read(); 3. a [1] = System.in.read(); 4. a [2] = System.in.read(); 5. assert(a [0] > 0); 6. assert(a [1] > 0); 7. assert(a [2] > 0); 8. int sum = 0; 9. int i = 0; 10. while (i < 3) { 11. if (sum == 0) 12. sum = sum+a [i]; 13. i = i+1; } 14. System.out.println(sum); } Symbolic values: [a[0] = A0] [.., a[1] = A1] [.., a[2] = A2] [.., sum = 0] [.., i = 0] [.., sum = A0] [.., i = 1] Symbolic guards: {(A0 > 0)} {.. (A1 > 0)} {.. (A2 > 0)} {.. (0 < 3)} {.. (0 = 0)} 41 9/15/10

Example symbolic execution 0. int main(string[] argv) { 1. int[] a = new int[3]; 2. a [0] = System.in.read(); 3. a [1] = System.in.read(); 4. a [2] = System.in.read(); 5. assert(a [0] > 0); 6. assert(a [1] > 0); 7. assert(a [2] > 0); 8. int sum = 0; 9. int i = 0; 10. while (i < 3) { 11. if (sum == 0) 12. sum = sum+a [i]; 13. i = i+1; } 14. System.out.println(sum); } Symbolic values: [a[0] = A0] [.., a[1] = A1] [.., a[2] = A2] [.., sum = 0] [.., i = 0] sum = if guard then A0 else ANY i = if guard then 1 else ANY Symbolic guards: {(A0 > 0)} {.. (A1 > 0)} {.. (A2 > 0)} {.. (0 < 3)} {.. (0 = 0)} 42 9/15/10

Example PC refinement Symbolic formula: (a[0] = A0) (a[1] = A1) (a[2] = A2) let c = (A0 > 0) (A1 > 0) (A2 > 0) and c = c (A0 = 0) in ((sum 2 = if c then 0 else ANY) (i 2 = if c then 0 else ANY)) ((sum 2 = if c then A0 else ANY) (i 2 = if c then 1 else ANY)) ((sum 2 = if c then A0 else ANY) (i 2 = if c then 2 else ANY)) ((sum 2 = if c then A0 else ANY) (i 2 = if c then 3 else ANY)) Current witness: a[0] = 15, a[1] = 5, a[2] = 42, i 1 = 0, i 2 = i 3 = 1, sum 1 = sum 2 = sum 3 = sum 4 = 0 (Initial symbolic values) (1 st iter) (2 nd iter) (3 rd iter) (4 th iter) FALSE 43 9/15/10

Example PC refinement Symbolic formula: (a[0] = A0) (a[1] = A1) (a[2] = A2) let c = (A0 > 0) (A1 > 0) (A2 > 0) and c = c (A0 = 0) in ((sum 2 = if c then 0 else ANY) (i 2 = if c then 0 else ANY)) ((sum 2 = if c then A0 else ANY) (i 2 = if c then 1 else ANY)) ((sum 2 = if c then A0 else ANY) (i 2 = if c then 2 else ANY)) ((sum 2 = if c then A0 else ANY) (i 2 = if c then 3 else ANY)) Current witness: a[0] = 15, a[1] = 5, a[2] = 42, i 1 = 0, i 2 = i 3 = 1, sum 1 = sum 2 = sum 3 = sum 4 = 0 (Initial symbolic values) (1 st iter) (2 nd iter) (3 rd iter) (4 th iter) Proof ((a[0] > 0) (a[1] > 0) (a[2] > 0)) ((sum 2 = 0 i 2 = 0) sum 2 = a[0]) 44 9/15/10

Path condition refinement Proof of unsatisfiability is A formula weaker than the one solved Is still unsatisfiable wrt the current witness That is, If Then F Sol false, Proof Sol false, and F Proof Refined PC is the previous PC augmented with the proof Refined PC = old PC Proof It guarantees that the current solution will never be found again 45 9/15/10

Example PC refinement PC (3, 14) PC(3, 14) Proof (a[0] > 0) (a[1] > 0) (a[2] > 0) (i 1 = 0) (i 2 = i 3 = 1) (sum 1 = sum 2 = sum 3 = sum 4 = 0) ((a[0] > 0) (a[1] > 0) (a[2] > 0) false ((sum 2 = 0 i 2 = 0) (sum 2 = a[0]))) No information flow is possible! 46 9/15/10

Final words CEGAR-based IFC is expected to be much more precise than PDGand PC-based IFC Incorporates a fully automatic solve-validate-refine loop Increases the precision of the analysis on demand Exploits constraint solving, concrete and symbolic executions, unsat proof Number of iterations depends on the richness of proofs and order of solutions returned by the solver A minimal proof is ideal, but not available Existing proofs have been shown to be good enough in practice In certain cases, termination requires a time-out threshold Because witness execution may not terminate Because PC can become intractable 47 9/15/10

Final words Status of the project PDG-based IFC implemented for full Java bytecode Handles around 50 kloc Path condition implemented for imperative Java Handles a few kloc CEGAR implementation just started Scalability reports will be available in the future 48 9/15/10

49 9/15/10

Related work security type systems Opened the door to language-based security analysis Compositional, scalable But require user-provided annotations Examples include JIF and Mobius Mobius augments type systems with proof-carrying code In PCC, code is accompanied by a certificate that can be efficiently checked by the code consumer that the code conforms to security policies Certificates can be produced via traditional verification, static analysis, type systems Compared to PDGs PDGs are much more expensive, less scalable But fewer false alarms (????) 50 9/15/10

Related work CEGAR So far applied very successfully to Software model checking Involves predicate abstraction Detects reachability of the error states in the context of temporal safety properties Examples include SLAM, BLAST Data structure analysis Uses proof of unsatisfiability Checks functional properties of structure-rich code But purely static, based on SAT solving, and finite domain analysis Examples include Karun CEGAR provides a scalable analysis by Analyzing code incrementally, only on demand Performing refinements locally 51 9/15/10