VigNAT: A Formally Verified NAT Arseniy Zaostrovnykh, Solal - - PowerPoint PPT Presentation

vignat a formally verified nat
SMART_READER_LITE
LIVE PREVIEW

VigNAT: A Formally Verified NAT Arseniy Zaostrovnykh, Solal - - PowerPoint PPT Presentation

VigNAT: A Formally Verified NAT Arseniy Zaostrovnykh, Solal Pirelli, Luis Pedrosa, Katerina Argyraki, George Candea Formally verify a stateful NF with competitive performance and reasonable human effort 2 Formally verify a stateful NF with


slide-1
SLIDE 1

VigNAT: A Formally Verified NAT

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

slide-2
SLIDE 2

2

Formally verify a stateful NF with competitive performance and reasonable human effort

slide-3
SLIDE 3

3

Formally verify a stateful NF with competitive performance and reasonable human effort

slide-4
SLIDE 4

Formally verify a stateful NF with competitive performance and reasonable human effort

4

slide-5
SLIDE 5

Software Network Functions: Pros and Cons

  • Everywhere

○ OpenWRT/NetFilter, Click, RouteBricks ○ Vyatta, OpenVswitch, DPDK

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

5

slide-6
SLIDE 6

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

slide-7
SLIDE 7

Testing: Easy but Incomplete

7

slide-8
SLIDE 8

Testing: Easy but Incomplete

8

slide-9
SLIDE 9

9

Formal Verification: Complete but Expensive

slide-10
SLIDE 10

10

Formal Verification: Complete but Expensive

——?——

slide-11
SLIDE 11

Network Verification

S D

11

slide-12
SLIDE 12

Network Verification

S D

CODE

12

MODEL

slide-13
SLIDE 13

Network Verification ≠ NF Code Verification

S D

CODE

13

slide-14
SLIDE 14

14

Bits Algebras Human effort quick slow (infeasible) Machine effort slow (infeasible) quick

How to Verify an NF (Before Vigor)?

slide-15
SLIDE 15

15

Bits Algebras Human effort quick slow (infeasible) Machine effort slow (infeasible) quick

How to Verify an NF (Before Vigor)?

slide-16
SLIDE 16

16

Bits Algebras Human effort quick slow (infeasible) Machine effort slow (infeasible) quick

How to Verify an NF (Before Vigor)?

slide-17
SLIDE 17

17

Bits Algebras Human effort quick slow (infeasible) Machine effort slow (infeasible) quick

How to Verify an NF (Before Vigor)?

slide-18
SLIDE 18

Bits Algebras Human effort quick high / infeasible Machine effort slow (infeasible) low

Theorem Proving

18

slide-19
SLIDE 19

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.

slide-20
SLIDE 20

Bits Algebras Human effort low high / infeasible Machine effort high / infeasible low

Exhaustive Symbolic Execution (SymbEx)

20

slide-21
SLIDE 21

Bits Algebras Human effort low high / infeasible Machine effort high / infeasible low

Exhaustive Symbolic Execution (SymbEx)

Credit to Jonas Wagner

Path Explosion

21

slide-22
SLIDE 22

Bits Algebras Human effort low high / infeasible Machine effort high / infeasible low

Vigor

22

slide-23
SLIDE 23

Bits Algebras Human effort low high / infeasible Machine effort high / infeasible low

Vigor

Plus runtime performance

23

slide-24
SLIDE 24

Main Idea

24

  • Split the code into two parts
  • Verify each part separately
  • Stitch the proofs — key challenge
slide-25
SLIDE 25

Outline

  • Problem Statement
  • VigNAT Formal Proof

○ General Idea ○ Proof Stitching Example

  • RFC Formalization
  • Performance

25

slide-26
SLIDE 26

Vigor: split code | verify parts | stitch proofs

26

CODE

slide-27
SLIDE 27

Vigor: split code | verify parts | stitch proofs

27

slide-28
SLIDE 28

Vigor: split code | verify parts | stitch proofs

28

slide-29
SLIDE 29

Stateful code (data structures) Stateless code (application logic)

29

Vigor: split code | verify parts | stitch proofs

Interface contracts

slide-30
SLIDE 30

Interface contracts Stateful code (data structures)

30

Vigor: split code | verify parts | stitch proofs

Theorem Proving

slide-31
SLIDE 31

Stateful code (data structures) Stateless code (application logic)

31

Vigor: split code | verify parts | stitch proofs

Interface contracts

slide-32
SLIDE 32

Stateful code (data structures) Stateless code (application logic)

32

Vigor: split code | verify parts | stitch proofs

Interface contracts

Exhaustive Symbolic Execution

slide-33
SLIDE 33

Stateless code (application logic)

33

Vigor: split code | verify parts | stitch proofs

Symbolic models

Exhaustive Symbolic Execution

Approximation (not trusted)

slide-34
SLIDE 34

Symbolic models Stateless code (application logic)

34

Vigor: split code | verify parts | stitch proofs

traces

Approximation (not trusted)

Exhaustive Symbolic Execution

slide-35
SLIDE 35

35

Vigor: split code | verify parts | stitch proofs

traces

Interface contracts

slide-36
SLIDE 36

Interface contracts

Vigor: split code | verify parts | stitch proofs

Vigor Validator

36

traces

slide-37
SLIDE 37

Interface contracts Stateful code (data structures) Stateless code (application logic)

Vigor: split code | verify parts | stitch proofs

Vigor Validator

37

traces Exhaustive Symbolic Execution Theorem Proving

slide-38
SLIDE 38

Outline

  • Problem Statement
  • VigNAT Formal Proof

○ General Idea ○ Proof Stitching Example

  • RFC Formalization
  • Performance

38

slide-39
SLIDE 39

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 contracts

39

slide-40
SLIDE 40

Example NF Code

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); }

40

slide-41
SLIDE 41

Example NF Code

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); }

41

slide-42
SLIDE 42

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

slide-43
SLIDE 43

For Each API Function ...

43

Symbolic model Formal contract

slide-44
SLIDE 44

Example: Formal Contract

void ring_pop_front(struct ring* r, struct packet* p);

r is not empty and p points to valid memory ———————————— r contains one packet less and p points to a packet and p->port ≠ 9

44

Formal contract

slide-45
SLIDE 45

Example: Symbolic Model

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

45

Symbolic model

slide-46
SLIDE 46

Example NF Code

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); }

46

slide-47
SLIDE 47

Use Symbolic Models

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); }

47

Symbolic model Symbolic model Symbolic model Symbolic model

slide-48
SLIDE 48

Execution Trace

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); }

48

slide-49
SLIDE 49

Execution Trace

if (!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); }

slide-50
SLIDE 50

Over-Approximation Proof

r1 = 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

slide-51
SLIDE 51

Over-Approximation Proof

r1 = 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

slide-52
SLIDE 52

Over-Approximation Proof

r1 = 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 Symbolic model

slide-53
SLIDE 53

Outline

  • Problem Statement
  • VigNAT Formal Proof

○ General Idea ○ Proof Stitching Example

  • RFC Formalization
  • Performance

53

slide-54
SLIDE 54

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

slide-55
SLIDE 55

flowtable

Formalization of the NAT RFC

NAT

packet packet

flowtable

55

time

slide-56
SLIDE 56

flowtable

Formalization of the NAT RFC

NAT

packet packet

NAT NAT

packet packet packet packet

56

time time time

flowtable flowtable

slide-57
SLIDE 57

Formalization of the NAT RFC

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

NAT

packet

57

packet time

flowtable flowtable

slide-58
SLIDE 58

packet

Formalization of the NAT RFC

58

time update/create flow expire_flows forward/drop

flowtable flowtable

slide-59
SLIDE 59

Outline

  • Problem Statement
  • VigNAT Formal Proof

○ General Idea ○ Proof Stitching Example

  • RFC Formalization
  • Performance

59

slide-60
SLIDE 60

Performance

No-op

(DPDK)

Unverified NAT

(DPDK)

VigNAT

(DPDK)

60

Linux NAT

(NetFilter)

slide-61
SLIDE 61

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

slide-62
SLIDE 62

~20 μsec

Performance

Throughput 2.0 Mpps 1.8 Mpps

62

0.6 Mpps

No-op

(DPDK)

Unverified NAT

(DPDK)

VigNAT

(DPDK)

Linux NAT

(NetFilter) Latency 5.13 μsec 5.03 μsec 4.63 μsec 3.2 Mpps

slide-63
SLIDE 63

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

slide-64
SLIDE 64

Verification Friendliness of NF Code

  • Low complexity

○ No long/unbounded loops (except main loop)

  • Well defined data structures
  • Often implements widely adopted standards

64

slide-65
SLIDE 65

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

slide-66
SLIDE 66

It is feasible now to build a stateful NF that have both competitive performance and formally verified semantic properties with reasonable effort

66

Interface contracts Stateful code (verified data structures) Stateless code (application logic)

Vigor Validator

traces

Exhaustive Symbolic Execution Theorem Proving

slide-67
SLIDE 67

Additional material

67

slide-68
SLIDE 68

Index

68

  • Experimental setup
  • DPDK performance report
  • Future work
  • NAT RFC formalization
  • Related work
  • Plots
  • Stitching details
  • Proof Structure
slide-69
SLIDE 69

Performance Experiment

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

Tester DUT

69

index

slide-70
SLIDE 70

Performance is comparable

<DPDK perf report>

70

index

slide-71
SLIDE 71

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 + …)

71

index

slide-72
SLIDE 72

RFC 3022 Formalization

72

index

slide-73
SLIDE 73

Related work

73

  • System software verification

seL4, CompCert, IronFleet, FSCQ, Beringer et al.

  • Interoperability testing / protocol specification

Musuvathi et al., Bishop et al., Kuzniar et al., PIC

  • Network configuration verification / testing

SymNet {+NF testing}, BUZZ, Batfish, HSA, VeriFlow, NoD, Anteater, Panda et al., Cocoon, Xie et al.

  • NF software verification : Dobrescu et al.

index

slide-74
SLIDE 74

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

74

index

slide-75
SLIDE 75

Latency

75

index

slide-76
SLIDE 76

Throughput

76

index

slide-77
SLIDE 77

Example: NF Code

#define CAP 512 int 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; }

77

index

slide-78
SLIDE 78

loop_iteration_begin(&X) => [] ring_full(&X) => true ring_empty(&X) => false can_send() => true ring_pop_front(&X, &{.port == y} -> &{.port == z}) => [] —— z != 9

#define CAP 512 int 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

78

index

slide-79
SLIDE 79

loop_iteration_begin(&X) => [] ring_full(&X) => true ring_empty(&X) => false can_send() => true ring_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);

79

index

slide-80
SLIDE 80

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: ... and packet satisfies packet_constraints_fp.

80

index

slide-81
SLIDE 81

Proof Structure

VigNAT satisfies semantic properties VigNAT satisfies low-level properties VigNAT stateless code respects the interface contracts symbolic models are faithful to the interface contracts Stateful implementations behaves according to the interface contracts

81

index