Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus...

46
Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011

Transcript of Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus...

Page 1: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Formal reasoning about runtime code update

Billiejoe (Nathaniel) Charlton

Ben Horsfall

Bernhard Reus

HotSWUp 2011

Page 2: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Outline

• Discuss how to do formal proofs about safety of runtime code updates

- Using a (relatively) new variant of Hoare logic

- specifically, Hoare logic with nested Hoare triples

Page 3: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Outline

• Discuss how to do formal proofs about safety of runtime code updates

- Using a (relatively) new variant of Hoare logic

- specifically, Hoare logic with nested Hoare triples

• Example of formally specifying safety of a runtime update

- for a model of an updateable web server from:

“Formalizing Dynamic Software Updating”

(Gavin Bierman, Michael Hicks, Peter Sewell, Gareth Stoyle)

Page 4: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Outline

• Discuss how to do formal proofs about safety of runtime code updates

- Using a (relatively) new variant of Hoare logic

- specifically, Hoare logic with nested Hoare triples

• Example of formally specifying safety of a runtime update

- for a model of an updateable web server from:

“Formalizing Dynamic Software Updating”

(Gavin Bierman, Michael Hicks, Peter Sewell, Gareth Stoyle)

- (time permitting) glimpse of this proof done in Crowfoot, our semi-automated verification tool

Page 5: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Hoare logic

• A formal logic for proving things - triples - about programs, e.g.

• Meaning: if we run the program in a state where the precondition holds

- then the program doesn’t crash

- and if it terminates, the postcondition will hold

Page 6: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Hoare logic

• A formal logic for proving things - triples - about programs, e.g.

• Meaning: if we run the program in a state where the precondition holds

- then the program doesn’t crash

- and if it terminates, the postcondition will hold [ ] = heap access (indirection)

Page 7: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Hoare logic

• A formal logic for proving things - triples - about programs, e.g.

• Meaning: if we run the program in a state where the precondition holds

- then the program doesn’t crash

- and if it terminates, the postcondition will hold

• BUT: Conventional Hoare logic assumes that program’s code is fixed

- because pre- and post-condition talk only about data, not code

- so how can one reason about dynamic software updates?

Page 8: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Key idea: nested Hoare triples

• Writing code onto the heap:

Page 9: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Key idea: nested Hoare triples

• Writing code onto the heap:

Page 10: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Key idea: nested Hoare triples

• Writing code onto the heap:

Page 11: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Key idea: nested Hoare triples

• Writing code onto the heap:

• Invoking code stored on the heap:

Page 12: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Key idea: nested Hoare triples

• Writing code onto the heap:

• Invoking code stored on the heap:

Page 13: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Key idea: nested Hoare triples

• Writing code onto the heap:

• Invoking code stored on the heap:

Page 14: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Nested Hoare triples

• Only understood recently

- because underlying mathematics is complicated

- started with [Honda, Yoshida, Berger - LICS 05]

- further developed by others since then

Page 15: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Nested Hoare triples

• Only understood recently

- because underlying mathematics is complicated

- started with [Honda, Yoshida, Berger - LICS 05]

- further developed by others since then

• Now we have the theory, can we use it to reason about programs?

- We thought: let’s give it a go

Page 16: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Nested Hoare triples

• Only understood recently

- because underlying mathematics is complicated

- started with [Honda, Yoshida, Berger - LICS 05]

- further developed by others since then

• Now we have the theory, can we use it to reason about programs?

- We thought: let’s give it a go

• We borrowed an example from the literature: a model of an updateable web server

- One particular runtime update: adding logging to the web server

- Code on slides is mercilessly pruned compared to our paper

Page 17: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

heapcell loop_h;

heapcell version;

proc main()

{

locals q;

[version] := 1;

q := new 0;

call mkQueue(q);

[loop_h] := loop(_);

eval [loop_h](q)

}

proc loop(q)

{

locals e;

e := new 0;

call getEvent(q,e);

call handleEvent(e);

call maybe_update();

eval [loop_h](q)

}

proc handleEvent(e) {...}

proc getEvent(q,e) {...}

proc mkQueue(q) {...}

This slide: initial version of model web server

Page 18: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

heapcell loop_h;

heapcell version;

proc main()

{

locals q;

[version] := 1;

q := new 0;

call mkQueue(q);

[loop_h] := loop(_);

eval [loop_h](q)

}

proc loop(q)

{

locals e;

e := new 0;

call getEvent(q,e);

call handleEvent(e);

call maybe_update();

eval [loop_h](q)

}

proc handleEvent(e) {...}

proc getEvent(q,e) {...}

proc mkQueue(q) {...}

Page 19: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

heapcell loop_h;

heapcell version;

proc main()

{

locals q;

[version] := 1; q := new 0;

call mkQueue(q);

[loop_h] := loop(_);

eval [loop_h](q)

}

proc loop(q)

{

locals e;

e := new 0;

call getEvent(q,e);

call handleEvent(e);

call maybe_update();

eval [loop_h](q)

}

proc handleEvent(e) {...}

proc getEvent(q,e) {...}

proc mkQueue(q) {...}

Record that we start at version 1

Page 20: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

heapcell loop_h;

heapcell version;

proc main()

{

locals q;

[version] := 1;

q := new 0;

call mkQueue(q); [loop_h] := loop(_);

eval [loop_h](q)

}

proc loop(q)

{

locals e;

e := new 0;

call getEvent(q,e);

call handleEvent(e);

call maybe_update();

eval [loop_h](q)

}

proc handleEvent(e) {...}

proc getEvent(q,e) {...}

proc mkQueue(q) {...}

Create a queue for events

Page 21: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

heapcell loop_h;

heapcell version;

proc main()

{

locals q;

[version] := 1;

q := new 0;

call mkQueue(q);

[loop_h] := loop(_); eval [loop_h](q)

}

proc loop(q)

{

locals e;

e := new 0;

call getEvent(q,e);

call handleEvent(e);

call maybe_update();

eval [loop_h](q)

}

proc handleEvent(e) {...}

proc getEvent(q,e) {...}

proc mkQueue(q) {...}

‘loop’ procedure kept on theheap, so we can update it later

Page 22: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

heapcell loop_h;

heapcell version;

proc main()

{

locals q;

[version] := 1;

q := new 0;

call mkQueue(q);

[loop_h] := loop(_);

eval [loop_h](q)}

proc loop(q)

{

locals e;

e := new 0;

call getEvent(q,e);

call handleEvent(e);

call maybe_update();

eval [loop_h](q)

}

proc handleEvent(e) {...}

proc getEvent(q,e) {...}

proc mkQueue(q) {...}

Page 23: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

heapcell loop_h;

heapcell version;

proc main()

{

locals q;

[version] := 1;

q := new 0;

call mkQueue(q);

[loop_h] := loop(_);

eval [loop_h](q)

}

proc loop(q)

{

locals e;

e := new 0;

call getEvent(q,e);

call handleEvent(e); call maybe_update();

eval [loop_h](q)

}

proc handleEvent(e) {...}

proc getEvent(q,e) {...}

proc mkQueue(q) {...}

Page 24: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

heapcell loop_h;

heapcell version;

proc main()

{

locals q;

[version] := 1;

q := new 0;

call mkQueue(q);

[loop_h] := loop(_);

eval [loop_h](q)

}

proc loop(q)

{

locals e;

e := new 0;

call getEvent(q,e);

call handleEvent(e);

call maybe_update(); eval [loop_h](q)

}

proc handleEvent(e) {...}

proc getEvent(q,e) {...}

proc mkQueue(q) {...}

Page 25: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

heapcell loop_h;

heapcell version;

proc main()

{

locals q;

[version] := 1;

q := new 0;

call mkQueue(q);

[loop_h] := loop(_);

eval [loop_h](q)

}

proc loop(q)

{

locals e;

e := new 0;

call getEvent(q,e);

call handleEvent(e);

call maybe_update();

eval [loop_h](q)}

proc handleEvent(e) {...}

proc getEvent(q,e) {...}

proc mkQueue(q) {...}

Page 26: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

heapcell loop_h;

heapcell version;

proc main()

{

locals q;

[version] := 1;

q := new 0;

call mkQueue(q);

[loop_h] := loop(_);

eval [loop_h](q)

}

proc loop(q)

{

locals e;

e := new 0;

call getEvent(q,e);

call handleEvent(e);

call maybe_update();

eval [loop_h](q)

}

proc handleEvent(e) {...}

proc getEvent(q,e) {...}

proc mkQueue(q) {...}

Page 27: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

What does our update do?

• Add logging to server – every event will be logged

• Overwrite ‘loop’ code with a new version

• Add three new procedures:

- loopPrime – the new event-handling loop

- logEvent – creates a log entry for a given event

- mkEmptyLog – used during transition to create an empty log

Page 28: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

heapcell loopPrime_h;

heapcell logEvent_h;

heapcell mkEmptyLog_h;

proc mkEmptyLog_2(log) {...}

proc logEvent_2(e,log) {...}

proc loop_2(q)

{

locals log;

log := new 0;

eval [mkEmptyLog_h](log);

eval [loopPrime_h](q,log)

}

proc loopPrime_2(q,log)

{

locals e;

e := new 0;

call getEvent(q,e);

eval [logEvent_h](e,log);

call handleEvent(e);

call maybe_update();

eval [loopPrime_h](q,log)

}

Page 29: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

heapcell loopPrime_h;

heapcell logEvent_h;

heapcell mkEmptyLog_h;

proc mkEmptyLog_2(log) {...}

proc logEvent_2(e,log) {...}

proc loop_2(q){

locals log;

log := new 0;

eval [mkEmptyLog_h](log);

eval [loopPrime_h](q,log)

}

proc loopPrime_2(q,log)

{

locals e;

e := new 0;

call getEvent(q,e);

eval [logEvent_h](e,log);

call handleEvent(e);

call maybe_update();

eval [loopPrime_h](q,log)

}

Replacement for ‘loop’:“transitional function” to take system into new version

Page 30: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

heapcell loopPrime_h;

heapcell logEvent_h;

heapcell mkEmptyLog_h;

proc mkEmptyLog_2(log) {...}

proc logEvent_2(e,log) {...}

proc loop_2(q)

{

locals log;

log := new 0;

eval [mkEmptyLog_h](log); eval [loopPrime_h](q,log)

}

proc loopPrime_2(q,log)

{

locals e;

e := new 0;

call getEvent(q,e);

eval [logEvent_h](e,log);

call handleEvent(e);

call maybe_update();

eval [loopPrime_h](q,log)

}

Set up an empty Log structure

Page 31: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

heapcell loopPrime_h;

heapcell logEvent_h;

heapcell mkEmptyLog_h;

proc mkEmptyLog_2(log) {...}

proc logEvent_2(e,log) {...}

proc loop_2(q)

{

locals log;

log := new 0;

eval [mkEmptyLog_h](log);

eval [loopPrime_h](q,log)}

proc loopPrime_2(q,log)

{

locals e;

e := new 0;

call getEvent(q,e);

eval [logEvent_h](e,log);

call handleEvent(e);

call maybe_update();

eval [loopPrime_h](q,log)

}

Pass control to the newevent handling loop

Page 32: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

heapcell loopPrime_h;

heapcell logEvent_h;

heapcell mkEmptyLog_h;

proc mkEmptyLog_2(log) {...}

proc logEvent_2(e,log) {...}

proc loop_2(q)

{

locals log;

log := new 0;

eval [mkEmptyLog_h](log);

eval [loopPrime_h](q,log)

}

proc loopPrime_2(q,log){

locals e;

e := new 0;

call getEvent(q,e);

eval [logEvent_h](e,log); call handleEvent(e);

call maybe_update();

eval [loopPrime_h](q,log)

}

new event handling loop

The new behaviour:Log every eventbefore processing

Page 33: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

proc maybe_update()

{

if [version] = 1 then

{

if nondet then { skip }

else

{

[version] := 2;

[loop_h] := loop_2(_);

[loopPrime_h] := loopPrime_2(_,_);

[logEvent_h] := logEvent_2(_,_);

[mkEmptyLog_h] := mkEmptyLog_2(_)

}

}

else { skip }

}

Non-deterministically decide whether to update or not

Page 34: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

proc maybe_update()

{

if [version] = 1 then

{

if nondet then { skip }

else

{

[version] := 2; [loop_h] := loop_2(_);

[loopPrime_h] := loopPrime_2(_,_);

[logEvent_h] := logEvent_2(_,_);

[mkEmptyLog_h] := mkEmptyLog_2(_)

}

}

else { skip }

}

Increment version number

Page 35: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

proc maybe_update()

{

if [version] = 1 then

{

if nondet then { skip }

else

{

[version] := 2;

[loop_h] := loop_2(_);

[loopPrime_h] := loopPrime_2(_,_);

[logEvent_h] := logEvent_2(_,_);

[mkEmptyLog_h] := mkEmptyLog_2(_)

}

}

else { skip }

}

Overwrite ‘loop’ with new version

Page 36: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

proc maybe_update()

{

if [version] = 1 then

{

if nondet then { skip }

else

{

[version] := 2;

[loop_h] := loop_2(_);

[loopPrime_h] := loopPrime_2(_,_);

[logEvent_h] := logEvent_2(_,_);

[mkEmptyLog_h] := mkEmptyLog_2(_) }

}

else { skip }

}

Load newprocedures onto heap

Page 37: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

What are we trying to prove?

We need to say what we are trying to prove!

- For each procedure we give a specification e.g. for ‘getEvent’:

- Concentrate on memory safety

- i.e. the right kind of data structures are present in the right place

- We won’t go into details of Queue, Event, Log predicates...

Page 38: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

To specify the effect of maybe_update(), we need this monster definition

Page 39: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Code(v) describes the kind of code present on the heap in version v

Page 40: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Code(v) is nested inside itself!

Page 41: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Specifications

For ‘loop’:

Page 42: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Specifications

For ‘loop’:

For ‘logEvent_2’:

Page 43: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Specifications

For ‘loop’:

For ‘logEvent_2’:

For ‘maybe_update’:

Page 44: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

• With these specifications we can prove the update safe

• Proof done semi-automatically by our verification tool

Page 45: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Summary

• Discussed how to do formal proofs about safety of runtime code updates

- using Hoare logic with nested triples

• Talked through how to formally specify safety of an update

- for a model of an updateable web server from:

“Formalizing Dynamic Software Updating”

(Bierman, Hicks, Sewell, Stoyle)

• (maybe) glimpsed Crowfoot, our semi-automated verification tool for such safety proofs

Page 46: Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

The End