Katerina Argyraki, George Candea Arseniy Zaostrovnykh ... · Arseniy Zaostrovnykh, Solal Pirelli,...

Preview:

Citation preview

VigNAT:A Formally Verified NAT

Arseniy Zaostrovnykh, Solal Pirelli, Luis Pedrosa, Katerina Argyraki, George Candea

2

Formally verify a stateful NF

with competitive performance

and reasonable human effort

3

Formally verify a stateful NF

with competitive performance

and reasonable human effort

Formally verify a stateful NF

with competitive performance

and reasonable human effort

4

Software Network Functions: Pros and Cons

● Everywhere○ OpenWRT/NetFilter, Click, RouteBricks

○ Vyatta, OpenVswitch, DPDK

● Flexibility, short time to market, but ...

5

Software Network Functions: Pros and Cons

● Everywhere○ OpenWRT/NetFilter, Click, RouteBricks

○ Vyatta, OpenVswitch, DPDK

● Flexibility, short time to market, but ...

● Bugs○ Packets of death, table exhaustion, denial of service

○ Cisco NAT, Juniper NAT, NetFilter, Windows ICS

○ Network outages already cost up to $700B/year 6

Testing: Easy but Incomplete

7

Testing: Easy but Incomplete

8

9

Formal Verification: Complete but Expensive

10

Formal Verification: Complete but Expensive——?——

Network Verification

S

D

11

Network Verification

S

D

CODE

12

MODEL

Network Verification ≠ NF Code Verification

S

D

CODE

13

14

Bits Algebras

Human effort quick slow (infeasible)

Machine effort slow (infeasible) quick

How to Verify an NF (Before Vigor)?

15

Bits Algebras

Human effort quick slow (infeasible)

Machine effort slow (infeasible) quick

How to Verify an NF (Before Vigor)?

16

Bits Algebras

Human effort quick slow (infeasible)

Machine effort slow (infeasible) quick

How to Verify an NF (Before Vigor)?

17

Bits Algebras

Human effort quick slow (infeasible)

Machine effort slow (infeasible) quick

How to Verify an NF (Before Vigor)?

Bits Algebras

Human effort quick high / infeasible

Machine effort slow (infeasible) low

Theorem Proving

18

Bits Algebras

Human effort quick high / infeasible

Machine effort slow (infeasible) low

Theorem Proving

Too complicated

19

[1] Klein, Gerwin, et al. "seL4: Formal verification of an OS kernel." Proceedings of the ACM SIGOPS 22nd symposium on Operating systems principles. ACM, 2009.

[2] Chen, Haogang, et al. "Using Crash Hoare logic for certifying the FSCQ file system." Proceedings of the 25th Symposium on Operating Systems Principles. ACM, 2015.

Bits Algebras

Human effort low high / infeasible

Machine effort high / infeasible low

Exhaustive Symbolic Execution (SymbEx)

20

Bits Algebras

Human effort low high / infeasible

Machine effort high / infeasible low

Exhaustive Symbolic Execution (SymbEx)

Credit to Jonas Wagner

Path Explosion

21

Bits Algebras

Human effort low high / infeasible

Machine effort high / infeasible low

Vigor

22

Bits Algebras

Human effort low high / infeasible

Machine effort high / infeasible low

Vigor

Plus runtime performance

23

Main Idea

24

● Split the code into two parts

● Verify each part separately

● Stitch the proofs — key challenge

Outline

● Problem Statement

● VigNAT Formal Proof

○ General Idea

○ Proof Stitching Example

● RFC Formalization

● Performance

25

Vigor: split code | verify parts | stitch proofs

26

CODE

Vigor: split code | verify parts | stitch proofs

27

Vigor: split code | verify parts | stitch proofs

28

Stateful code(data structures)

Stateless code(application logic)

29

Vigor: split code | verify parts | stitch proofs

Interface contracts

Interface contractsStateful code

(data structures)

30

Vigor: split code | verify parts | stitch proofs

Theorem Proving

Stateful code(data structures)

Stateless code(application logic)

31

Vigor: split code | verify parts | stitch proofs

Interface contracts

Stateful code(data structures)

Stateless code(application logic)

32

Vigor: split code | verify parts | stitch proofs

Interface contracts

ExhaustiveSymbolic Execution

Stateless code(application logic)

33

Vigor: split code | verify parts | stitch proofs

Symbolic models

ExhaustiveSymbolic Execution

Approximation (not trusted)

Symbolic models Stateless code

(application logic)

34

Vigor: split code | verify parts | stitch proofs

traces

Approximation (not trusted)

ExhaustiveSymbolic Execution

35

Vigor: split code | verify parts | stitch proofs

traces

Interface contracts

Interface contracts

Vigor: split code | verify parts | stitch proofs

Vigor Validator

36

traces

Interface contractsStateful code

(data structures)Stateless code

(application logic)

Vigor: split code | verify parts | stitch proofs

Vigor Validator

37

traces

ExhaustiveSymbolic ExecutionTheorem Proving

Outline

● Problem Statement

● VigNAT Formal Proof

○ General Idea

○ Proof Stitching Example

● RFC Formalization

● Performance

38

Proof Stitching: SymbEx + Theorem Proving

● Stateful code: theorem proving● Stateless code: exhaustive symbolic execution

1. Use symbolic models — rough interpretations of contracts

● Symbolic models are written in C

2. Replay call traces in a proof checker to check contracts39

Example NF Codeif (!ring_full(r) && receive(&p) && p.port != 9)

ring_push_back(r, &p);

if (!ring_empty(r) && can_send()) {

ring_pop_front(r, &p);

send(&p);

}

40

Example NF Codeif (!ring_full(r) && receive(&p) && p.port != 9)

ring_push_back(r, &p);

if (!ring_empty(r) && can_send()) {

ring_pop_front(r, &p);

send(&p);

}

41

if (!ring_full(r) && receive(&p) && p.port != 9)

ring_push_back(r, &p);

if (!ring_empty(r) && can_send()) {

ring_pop_front(r, &p);

send(&p);

}

42

Example NF Code

For Each API Function ...

43

Symbolicmodel

Formal contract

Example: Formal Contractvoid ring_pop_front(struct ring* r, struct packet* p);r is not empty andp points to valid memory ———————————— r contains one packet less andp points to a packet and p->port ≠ 9

44

Formal contract

Example: Symbolic Modelvoid ring_pop_front(struct ring* r, struct packet* p) { FILL_SYMBOLIC(p, sizeof(struct packet), "popped_packet"); ASSUME(p->port != 9);}

45

Symbolicmodel

Example NF Codeif (!ring_full(r) && receive(&p) && p.port != 9)

ring_push_back(r, &p);

if (!ring_empty(r) && can_send()) {

ring_pop_front(r, &p);

send(&p);

}

46

Use Symbolic Modelsif (!ring_full(r) && receive(&p) && p.port != 9)

ring_push_back(r, &p);

if (!ring_empty(r) && can_send()) {

ring_pop_front(r, &p);

send(&p);

}

47

Symbolicmodel

Symbolicmodel

Symbolicmodel

Symbolicmodel

Execution Traceif (!ring_full(r) && receive(&p) && p.port != 9)

ring_push_back(r, &p);

if (!ring_empty(r) && can_send()) {

ring_pop_front(r, &p);

send(&p);

}

48

Execution Traceif (!ring_full(r); assume(r1 → true

ring_push_back(r, &p);

if (!ring_empty(r); assume(r1 → false

ring_pop_front(r, &p): after(p.port ≠ 9)

49

if (!ring_full(r) && receive(&p) && p.port != 9)

ring_push_back(r, &p);

if (!ring_empty(r) && can_send()) {

ring_pop_front(r, &p);

send(&p);

}

Over-Approximation Proofr1 = ring_full(r); assume(r1 == true);

ring_push_back(r, &p);

r2 = ring_empty(r); assume(r2 == false);

ring_pop_front(r, &p);

assert(p.port ≠ 9);

50

Over-Approximation Proofr1 = ring_full(r); assume(r1 == true);

ring_push_back(r, &p);

r2 = ring_empty(r); assume(r2 == false);

ring_pop_front(r, &p);

assert(p.port ≠ 9);

51

Formal contract

Over-Approximation Proofr1 = ring_full(r); assume(r1 == true);

ring_push_back(r, &p);

r2 = ring_empty(r); assume(r2 == false);

ring_pop_front(r, &p);

assert(p.port ≠ 9);

52

⊂(covers)

Formal contract

Symbolicmodel

Outline

● Problem Statement

● VigNAT Formal Proof

○ General Idea

○ Proof Stitching Example

● RFC Formalization

● Performance

53

Formalization of the NAT RFC

● Everything happens at packet arrival

● Abstract flow table summarizes history of previous interactions

● Packet arrival timestamps — the only source of time

54

flowtable

Formalization of the NAT RFC

NATpacketpacket

flowtable

55

time

flowtable

Formalization of the NAT RFC

NATpacketpacket

NAT

NAT

packet

packet

packet

packet

56

time

time

time

flowtable

flowtable

Formalization of the NAT RFC

{flowtablebefore, time, packetin} ➡ {flowtableafter, packetout}

NAT packet

57

packet

timeflowtable

flowtable

packet

Formalization of the NAT RFC

58

time

update/create flow

expire_flows

forward/drop

flowtable

flowtable

Outline

● Problem Statement

● VigNAT Formal Proof

○ General Idea

○ Proof Stitching Example

● RFC Formalization

● Performance

59

PerformanceNo-op(DPDK)

Unverified NAT(DPDK)

VigNAT(DPDK)

60

Linux NAT(NetFilter)

Performance

61

Latency ~20 μsec

No-op(DPDK)

Unverified NAT(DPDK)

VigNAT(DPDK)

Linux NAT(NetFilter)

5.13 μsec

5.03 μsec

4.63 μsec

~20 μsec

Performance

Throughput 2.0Mpps

1.8Mpps 62

0.6Mpps

No-op(DPDK)

Unverified NAT(DPDK)

VigNAT(DPDK)

Linux NAT(NetFilter)

Latency 5.13 μsec

5.03 μsec

4.63 μsec

3.2Mpps

Human Effort (in Lines of Code)

Stateless code Stateful code(data structures)

Symbolic models Proofs of data structure library

800 1 000 400 + 325 (unvalidated DPDK)

23 000

63

Expect to reuse across many NFs

VigNAT Code Proof

Verification Friendliness of NF Code

● Low complexity○ No long/unbounded loops (except main loop)

● Well defined data structures

● Often implements widely adopted standards

64

Summary

● Vigor = symbolic execution + theorem proving

○ Stitching them is our primary contribution

● VigNAT is formally verified to comply with RFC 3022

○ Competitive performance

○ Tractable verification effort

65

It is feasible now to build a stateful NF that have both

competitive performance andformally verified semantic properties

with reasonable effort 66

Interface contractsStateful code

(verified data structures)Stateless code

(application logic)

Vigor Validator

traces

ExhaustiveSymbolic ExecutionTheorem Proving

Additional material

67

Index

68

● Experimental setup● DPDK performance report● Future work● NAT RFC formalization● Related work● Plots● Stitching details● Proof Structure

Performance Experiment

● RFC 2544● Intel Xeon E5-2667 v2 @ 3.30 GHz● 32 GB of DRAM● 82599ES 10 Gbps

Tester

DUT

69index

Performance is comparable

<DPDK perf report>

70index

Future Work

● Certify more NFs○ bridge with mac-learning,○ DMZ

● Improve automation (to reduce the effort and TCB)○ Invariant induction○ Symbolic model selection/generation

● Support Concurrency● Full system verification (Vigor + CompCert + seL4 + …)

71index

RFC 3022 Formalization

72index

Related work

73

● System software verificationseL4, CompCert, IronFleet, FSCQ, Beringer et al.

● Interoperability testing / protocol specificationMusuvathi et al., Bishop et al., Kuzniar et al., PIC

● Network configuration verification / testingSymNet {+NF testing}, BUZZ, Batfish, HSA, VeriFlow, NoD, Anteater, Panda et al., Cocoon, Xie et al.

● NF software verification : Dobrescu et al.index

Challenges

● Code

○ complexity from SymbEx viewpoint

○ unbounded number of events

○ arbitrary external interactions

● Formalize the RFC in machine readable language

● Integrate symbolic execution and theorem proving

74index

Latency

75index

Throughput

76index

Example: NF Code #define CAP 512int main() { struct packet p; struct ring *r = ring_create(CAP); if (!r) return 1; while(VIGOR_LOOP(1)) { loop_iteration_begin(&r); if (!ring_full(r)) if (receive(&p) && p.port != 9) ring_push_back(r, &p); if (!ring_empty(r) && can_send()) { ring_pop_front(r, &p); send(&p); } loop_iteration_end(&r); } return 0;} 77index

loop_iteration_begin(&X) => []ring_full(&X) => truering_empty(&X) => falsecan_send() => truering_pop_front(&X, &{.port == y} -> &{.port == z}) => []——z != 9

#define CAP 512int main() { struct packet p; struct ring *r = ring_create(CAP); if (!r) return 1; while(VIGOR_LOOP(1)) { loop_iteration_begin(&r); if (!ring_full(r)) if (receive(&p) && p.port != 9) ring_push_back(r, &p); if (!ring_empty(r) && can_send()) { ring_pop_front(r, &p); send(&p); } loop_iteration_end(&r); } return 0;}

SymbEx→ Theorem Proving:Trace

78index

loop_iteration_begin(&X) => []ring_full(&X) => truering_empty(&X) => falsecan_send() => truering_pop_front(&X, &{.port == y} -> &{.port == z}) => []——z != 9

SymbEx→ Theorem Proving:Replay

struct ring* arg1;struct packet arg2;

loop_invariant_produce(&(arg1));//@ open loop_invariant(_);bool ret1 = ring_full(arg1);//@ assume(ret1 == true);bool ret2 = ring_empty(arg1);//@ assume(ret2 == false);bool ret3 = can_send();//@ assume(ret3 == true);/*@ close packetp(&(arg2), packet((&(arg2))->port));@*/ring_pop_front(arg1, &(arg2));//@ open packetp(&(arg2), _);

//@ assert(arg2.port != 9);79index

struct ring* arg1;struct packet arg2;

loop_invariant_produce(&(arg1));//@ open loop_invariant(_);bool ret1 = ring_full(arg1);//@ assume(ret1 == true);bool ret2 = ring_empty(arg1);//@ assume(ret2 == false);bool ret3 = can_send();//@ assume(ret3 == true);/*@ close packetp(&(arg2), packet((&(arg2))->port));@*/ring_pop_front(arg1, &(arg2));//@ open packetp(&(arg2), _);

//@ assert(arg2.port != 9);

SymbEx→ Theorem Proving:Replay

void ring_pop_front(struct ring* ...);Contract: ... andpacket satisfies packet_constraints_fp.

80index

Proof Structure VigNAT satisfies semantic properties

VigNAT satisfieslow-level properties

VigNAT stateless coderespects the

interface contracts

symbolic models are faithful to the

interface contracts

Stateful implementations behaves according to the

interface contracts

81index

Recommended