policy enforcement and refinement
DESCRIPTION
Policy Enforcement and Refinement. Douglas R. Smith Kestrel Institute Palo Alto, California. Issue: How to Handle Nonfunctional and Cross-Cutting Concerns wrt Composition and Refinement?. A concern is cross-cutting if its manifestation cuts across the - PowerPoint PPT PresentationTRANSCRIPT
Kestrel
Issue: How to Handle Nonfunctional and Cross-Cutting Concerns wrt
Composition and Refinement?
A concern is cross-cutting if its manifestation cuts across the
dominant hierarchical structure of a program/system.
Examples
• Log all errors that arise during system execution
• Enforce a system-wide error-handling policy
• Disallow unauthorized data accesses
• Enforce timing and resource constraints on a system design
Kestrel
A Generative Approach to
Aspect-Oriented Programming
hypothesis: aspects are invariants to maintain
Kestrel
Crosscutting in AspectJ
aspect ObserverUpdating { pointcut moves(): calls(void Line.setP1(Point)) || calls(void Line.setP2(Point)) || calls(void Point.setX(int)) || calls(void Point.setY(int)) || calls(void FigureElement.incrXY());
after(): moves() { Display.update(); }}
Point
getX()getY()setX(int)setY(int)incrXY()
Line
getP1()getP2()setP1(Point)setP2(Point)incrXY()
Display *
2
*
crosscutting(one form of it)
FigureElement
incrXY()
Kestrel
Issues with current approaches toAspect-Oriented Programming
• What is the intention of an aspect?
• When is an aspect correct?
• Is the pointcut complete?
• What if the advice needs to cater for various contexts?
• Do two aspects conflict? How do we treat them?
• What if an aspect is not a pointwise action, but a behavior?
Kestrel
Expressing System Constraints
Many systems constraints refer to
• history (events, actions, state,…)
• dynamic context (i.e. the call-stack)
• environment behavior
• substrate properties (e.g. instruction timing, latence, …)
Kestrel
Virtual Variables in State
S0
act0 S1act1 S3 •••S2
act2hist := S0, act0 hist := hist ::S1, act1 hist := hist ::S2, act2
key idea: extend state with a virtual history variable
Virtual variables • exist for purposes of specification• sliced away prior to code generation
Kestrel
Maintain an Error Log
Policy: Maintain an error log in a system
Assume: errlog = filter(error?, actions(hist)) Achieve: errlog´ = filter(error?, actions(hist´))
spec satisfied by: errlog := errlog :: erract
Invariant: errlog = filter(error?, actions(hist))
Disruptive Actions: error?(act)
Spec for Maintenance Code : for each error action erract,
= filter(error?, actions(hist :: S, erract)) = filter(error?, actions(hist) :: erract)
= filter(error?, actions(hist)) :: erract = errlog :: erract
Kestrel
Maintaining an Error Log
S0
act0 S1hist := S0, act0
error1 S3 •••hist := hist ::S1, act1
S2act2
hist := hist ::S2, act2errlog := errlog errlog := errlog::error1 errlog := errlog
Kestrel
General Case
Invariant: I(x)
Disruptive Actions: any action that changes x or an alias
Spec for Maintenance Code : for each such action act with specification
Assume: P(x) Achieve: Q(x, x´)
generate and satisfy new specificationAssume: P(x) I(x) Achieve: Q(x, x´) I(x´)
spec typically satisfied by code of the form: act || update
Kestrel
Summary
• What is the intention of the aspect? expressed by an invariant
• Is the aspect code correct? yes, by construction
• Is the pointcut complete? static analysis finds all actions that disrupt the invariant
• Is the advice efficient in all contexts? specialized code generated for each context
• What if several aspects apply at a program point? attempt to satisfy the joint specification
• What if an aspect is not a pointwise action, but a behavior?enforcement of policy automata
Kestrel
Enforce a Security Policy
Policy: No send actions allowed after file f is read
aA B C D E F
read(f ) send(m)
read(f )One Two
send(*)policy automaton:
Build simulation map, then generate new code for corresponding actions
Inconsistent joint action spec: send(*) send(m) satisfied by abort action
Kestrel
Error-Handling Policiesand their Enforcement
Douglas R. Smith
Klaus Havelund
Kestrel Technology
Palo Alto, California
www.kestreltechnology.com
Kestrel
NonRobust Java Program
class AddNumbersFromFile {
static void doIt(String fileName) throws IOException { DataInputStream source = null; if (fileName != null) source = new DataInputStream(new FileInputStream(fileName)); int count = source.readInt(); int sum = addEm(source,count); System.out.println("Sum is " + sum); }
static int addEm(DataInputStream s, int c) throws IOException { int sum = 0; for (int i = 0; i < c; i++) sum += s.readInt(); if (s.available() == 0) s.close(); return sum; }}
Kestrel
Generic File Management Policy
Open Stopopen close
use
FileNotFoundException / handler1
IOException / handler2
use
handler3
Start
Error
Kestrel
Generic/Library Policy for DataInputStream’s
policy DataInputStreamPolicy { string filename; DataInputStream in;
Start: { DataInputStream(FileInputStream(filename)) returns in } -> Open
Start: { in.read*() } -> Error replace {throw new Error("Attempt to read from an unopen File"); }
Start: { in.available() } -> Start replace {throw new Error("Attempt to invoke available on an unopen File");}
Start: { in.close() } -> Start replace {print("Attempt to close an unopen File"); }
…
policy instance variables
Kestrel
Library Policy (continued)
Open: { in.read*() } -> Open catch (EOFException e) {throw new Error("EOF: insufficient data in file " + filename); } catch (IOException e) {throw new Error("Cannot read from File " + filename); } Open: { in.available() } -> Open catch (IOException e) {throw new Error("Unable to determine whether file " + filename + " contains more data"); } Open: { in.close() } -> Closed precondition {in.available() == 0} {System.out.println("Closed file " + filename + " when it contained extra data"); } Open : { exit } -> Closed preaction { System.out.println("Performing a missing close on file " + filename); in.close();
…
Kestrel
Example Policy (continued)
Closed: { in.read*() } -> Closed replace {throw new Error ("File " + filename + "already closed"); } Closed: { in.available() } -> Closed replace {throw new Error ("Attempt to invoke available on a closed file: " + filename); } Closed: { in.close() } -> Closed replace {throw new Error ("File " + filename + "already closed"); }
}
Kestrel
Application-Specific subPolicy for DataInputStreams
policy AddNumbersPolicy extends DataInputStreamPolicy {
Open0: { count = in.read*() } -> Open1 postcondition (0 <= count && count <= 1000) {System.out.println("count received an illegal value: " + Integer.toString(count) + "\nsetting count to 0"); count = 0;} catch (EOFException e) {throw new Error("File " + in.filename + " contains no data!"); } Open1: { in.read*() } -> Open1 }
Kestrel
Policy Simulation on the Example ProgramDoIt entry
fileName != null
Fsource = new DataInputStreamPolicy(fileName)
T
{Start}
{Start}{Open}
{Start,Open}
count = source.readInteger();
{Open}
call addEm(source,count);
{Open Closed, Open Open }
sum = result
{Open,Closed}
System.out.println("Sum is " + sum)
{Open,Closed}
exit
addEm entry
{Open}
sum = 0; i= 0;
i < c
sum += source.readInteger();i++;
T
s.available()==0
F
Fs.close();
T
{Open}
{Closed}
{Open, Closed}
{Open}
{Open}
{Open}
{Open}
{Open}
exit
return sum
{Open, Closed}
ambiguousanalysis
Kestrel
Program Transformation to Reduce Policy Ambiguity
if ( fileName != null ) source = new DataInputStream(new FileInputStream(fileName)); count = source.readInt();
if ( fileName != null ){ source = new DataInputStream(new FileInputStream(fileName)); count = source.readInt(); } else { count = source.readInt(); }
distribute if-then-else over semicolon
if ( fileName == null ) throw new Error("Attempt to read from an unopen File"); source = new DataInputStream(new FileInputStream(fileName)); count = source.readInt();
apply the policy and simplify
hasambiguous
analysis
hasunambiguous
analysis!
unambiguousanalysis,
clear code
Kestrel
Revised Java Program with Unambiguous Analysis
class AddNumbersFromFile {
static void doIt(String fileName) throws IOException { DataInputStream source = null; if ( fileName == null ) {throw new Error("Attempt to read from an unopen File");} source = new DataInputStream(new FileInputStream(fileName)); count = source.readInt(); int sum = addEm(source,count); System.out.println("Sum is " + sum); }
static int addEm(DataInputStream s, int c) throws IOException { int sum = 0; for (int i = 0; i < c; i++) sum += s.readInt();// if (s.available()==0) s.close(); return sum; }}
Kestrel
Policy-Specific Tracking Code (unambiguous case)
public class DataInputStreamForAddNumbers1 extends DataInputStream { public String filename;
public DataInputStreamForAddNumbers1(String filename) throws FileNotFoundException { super(new FileInputStream(filename)); // field in stores the file handle this.filename = filename; }}
HandlErr would generate an extension of the DataInputStream classthat records the policy instance bindings for the in error-handlers.
Kestrel
Revised Java Program with Enforced Policyclass RobustlyAddNumbersFromFile1 {
static void doIt(String fileName) throws IOException{ DataInputStreamForAddNumbers1 source = null; if ( fileName==null ){ throw new Error("Attempt to read from an unopen File"); } try { source = new DataInputStreamForAddNumbers1(fileName); } catch (FileNotFoundException e) { throw new Error("File " + fileName + " cannot be found"); } int count = 0; try { count = source.readInt(); } catch(EOFException e){ source.close(); throw new Error("File " + source.filename + " contains no data!"); } catch(IOException e){ source.close(); throw new Error("Bad data in file" + source.filename); } …
Kestrel
Policy Simulation on the Example ProgramDoIt entry
fileName != null
Fsource = new DataInputStreamPolicy(fileName)
T
{Start}
{Start}{Open}
{Start,Open}
count = source.readInteger();
{Open}
call addEm(source,count);
{Open Closed, Open Open }
sum = result
{Open,Closed}
System.out.println("Sum is " + sum)
{Open,Closed}
exit
addEm entry
{Open}
sum = 0; i= 0;
i < c
sum += source.readInteger();i++;
T
s.available()==0
F
Fs.close();
T
{Open}
{Closed}
{Open, Closed}
{Open}
{Open}
{Open}
{Open}
{Open}
exit
return sum
{Open, Closed}
ambiguousanalysis
Kestrel
Ambiguous Analysis
If the analysis remains ambiguous,then some form of runtime tracking of state is required, and runtime enforcement decisions.
Technique: use subclassing to track state
Kestrel
Generic File Management Policy
Open Stopopen close
use
FileNotFoundException / handler1
IOException / handler2
use
handler3
Start
Error
Kestrel
Runtime State Tracking
public class DataInputStreamForAddNumbers extends DataInputStream { public static final int Start = 1; public static final int Open = 2; public static final int Closed = 3; int currentState = Start; public String filename;
public DataInputStreamForAddNumbers(String filename) throws FileNotFoundException { super(new FileInputStream(filename)); // field in stores the file handle this.filename = filename; this.currentState = Open; }
public boolean inState(int state){ return this.currentState == state; }
Kestrel
Ambiguous Analysis
public int readInteger() throws IOException, EOFException{ int x = 0; switch(currentState){ case Start: throw new Error("Attempt to read from an unopen File"); case Open: try{ x = super.readInt(); } catch (EOFException e){ throw new EOFException("File" + filename + "contains no data!"); } catch (IOException e){ throw new IOException("Cannot read from file " + filename); } break; case Closed: throw new Error("File " + filename + "already closed"); } return x; }
Kestrel
Robustified Source – Ambiguous Case with state tracking and error-handling inside method calls
public class RobustAddNumbersFromFile {
static void doIt (String fileName) throws IOException { DataInputStreamForAddNumbers source = null; if ( fileName != null ) source = new DataInputStreamForAddNumbers(fileName); int count = source.readInteger(); int sum = addEm(source,count); System.out.println("Sum is " + sum); }
static int addEm(DataInputStreamForAddNumbers s, int c) throws IOException { int sum = 0; for (int i = 0; i < c; i++) sum += source.readInteger(); if ( s.available() == 0 ) s.close(); return sum; }}