Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Model Checking (what may become part of) the BP...

Avatar for shunghsiyu shunghsiyu
November 12, 2023

Model Checking (what may become part of) the BPF Verifier

Using model checking to validate a new data structure and algorithms for value tracking within Linux Kernel's BPF verifier.

See https://hackweek.opensuse.org/23/projects/model-checking-the-bpf-verifier for more details.

Avatar for shunghsiyu

shunghsiyu

November 12, 2023
Tweet

More Decks by shunghsiyu

Other Decks in Technology

Transcript

  1. Copyright © SUSE 10 NOVEMBER 20231 Model Checking (what may

    become part of) the BPF Verifier Hackweek 23, Shung-Hsi Yu
  2. Copyright © SUSE Allows users to supply code that will

    run in kernel context, useful for customizing system’s behavior towards user’s desire: — Networking — Tracing — Security BPF 2
  3. Copyright © SUSE — Project can be found on the

    Hack Week website — Use model checking to validate the tnum_add() algorithm – already done by the Sound, precise, and fast abstract interpretation with tristate numbers work – I’m just learning through mimicking Last year at Hack Week 21 Previous progress 3
  4. Copyright © SUSE — Re-open the same project — Implementing

    a more efficient way to do value tracking — Confirm that the new algorithms works with model checking — Submitted a draft PR to upstream – received initial feedback from Alexei Starovoitov (one of the maintainers of BPF subsystem) Hack Week 23 Progress so far this year 4
  5. Copyright © SUSE Check that user-supplied code does not: —

    Crash the kernel — Access data it is not suppose to read/write e.g. CVE-2021-3490 privilege escalation vulnerabilities Need to ensure that the BPF verifier is bug-free (as much as possible) BPF Verifier 6
  6. Copyright © SUSE int arr[10]; /* Is access() ever called

    with `i` greater than 10? */ int access(int i) { return arr[i]; /* access out-of-bound? */ } An example Value Tracking 7
  7. Copyright © SUSE int access(int i); /* `i` must NOT

    be greater than 10 */ void main(void) { int i; i = 1; /* `i` is surely 1 */ access(i); /* 1 < 10, so ok */ } An example Value Tracking 8
  8. Copyright © SUSE int access(int i); /* `i` must NOT

    be greater than 10 */ void main(void) { int i; i = 2023; /* `i` is surely 2023 */ access(i); /* 2023 > 10, so NOT ok */ } An example Value Tracking 9
  9. Copyright © SUSE static int i; /* global variable */

    void main(void) { /* `i` can be anything from INT_MIN to INT_MAX */ access(i); /* INT_MAX > 10, so NOT ok */ } An example Value Tracking 10
  10. Copyright © SUSE static int i; /* global variable */

    void main(void) { /* `i` can be anything from INT_MIN to INT_MAX */ if (0 < i && i < 2) /* `i` can be 0 to 2 */ access(i); /* 2 < 10, so ok */ } An example Value Tracking 11
  11. Copyright © SUSE static int i; /* global variable */

    void main(void) { /* `i` can be anything from INT_MIN to INT_MAX */ if (0 < i && i < 2) /* `i` can be 0 to 2 */ i = i + 5 /* `i` can be 5 to 7 */ access(i); /* 7 < 10, so ok */ } An example Value Tracking 12
  12. Copyright © SUSE static int i, j; /* global variable

    */ void main(void) { /* `i`, `j` can be anything from INT_MIN to INT_MAX */ if (0 < i && i < 2) /* `i` can be 0 to 2 */ if (0 < j && j < 4) /* `j` can be 0 to 4 */ /* i + j can be 0 to 6 */ access(i + j); /* 6 < 10, so ok */ } An example Value Tracking 13
  13. Copyright © SUSE BPF Verifier tracks the range of possible

    value similar to previous reasoning, by tracking possible value through minimum and maximum struct range { int min; int max; } In the Linux Kernel Value Tracking 14
  14. Copyright © SUSE … and implement corresponding operation that work

    on the range e.g. for addition we’d have a range_add() function /* Takes two range and adds them */ struct range range_add(struct range a, struct range b) { ... } In the Linux Kernel Value Tracking 15
  15. Copyright © SUSE … and implement corresponding operation that work

    on the range e.g. for addition we’d have a range_add() function /* Takes two range and adds them */ struct range range_add(struct range a, struct range b) { return (struct range){ .min=a.min+b.min, .max=a.max+b.max } } In the Linux Kernel Value Tracking 16
  16. Copyright © SUSE … and implement corresponding operation that work

    on the range e.g. for addition we’d have a range_add() function but does it work? /* Takes two range and adds them */ struct range range_add(struct range a, struct range b) { return (struct range){ .min=a.min+b.min, .max=a.max+b.max } } In the Linux Kernel Value Tracking 17 ?
  17. Copyright © SUSE Check with unit tests struct range a

    = { .min=0, .max=2 }; struct range b = { .min=0, .max=4 }; struct range r = range_add(a, b); assert(r.min == 0 && r.max == 6); Are There Bug(s)? 19
  18. Copyright © SUSE But we can’t cover all the possible

    cases it would take at least 232 cases to cover them all Are There Bug(s)? 20
  19. Copyright © SUSE Instead of testing case by case, try

    to check some abstract property Model Checking 21
  20. Copyright © SUSE To do so, first create a copy

    of algorithm using the modeling DSL Model Checking 22
  21. Copyright © SUSE To do so, first create a copy

    of algorithm using the modeling DSL Model Checking 23 struct range range_add(struct range a, struct range b) { return (struct range){ .min=a.min+b.min, .max=a.max+b.max } }
  22. Copyright © SUSE To do so, first create a copy

    of algorithm using the modeling DSL Model Checking 24 struct range range_add(struct range a, struct range b) { return (struct range){ .min=a.min+b.min, .max=a.max+b.max } } from z3 import * def range_add(a: Range, b: Range): # Python new_min = a.min + b.start new_max = a.max + b.end return range(min=new_start, max=new_max)
  23. Copyright © SUSE To do so, first create a copy

    of algorithm using the modeling DSL Model Checking 25 from z3 import * def range_add(a: Range, b: Range): # Python new_min = a.min + b.start new_max = a.max + b.end return range(min=new_start, max=new_max) struct range range_add(struct range a, struct range b) { return (struct range){ .min=a.min+b.min, .max=a.max+b.max } } C implementation
  24. Copyright © SUSE To do so, first create a copy

    of algorithm using the modeling DSL Model Checking 26 struct range range_add(struct range a, struct range b) { return (struct range){ .min=a.min+b.min, .max=a.max+b.max } } from z3 import * def range_add(a: Range, b: Range): # Python new_min = a.min + b.start new_max = a.max + b.end return range(min=new_start, max=new_max) “model” of the above implementation
  25. Copyright © SUSE x = Int('x'); y = Int('y') r1

    = Range('r1'); r2 = Range('r2') rsum = range_add(r1, r2) premise = And(r1.contains(x), r2.contains(y)) prove( Implies( premise, rsum.contains(x + y))) Model Checking 27
  26. Copyright © SUSE x = Int('x'); y = Int('y') r1

    = Range('r1'); r2 = Range('r2') rsum = range_add(r1, r2) premise = And(r1.contains(x), r2.contains(y)) prove( Implies( premise, rsum.contains(x + y))) Model Checking 28 model checking for range_add()
  27. Copyright © SUSE x = Int('x'); y = Int('y') r1

    = Range('r1'); r2 = Range('r2') rsum = range_add(r1, r2) premise = And(r1.contains(x), r2.contains(y)) prove( Implies( premise, rsum.contains(x + y))) Model Checking 29 say we have to integer x and y
  28. Copyright © SUSE x = Int('x'); y = Int('y') r1

    = Range('r1'); r2 = Range('r2') rsum = range_add(r1, r2) premise = And(r1.contains(x), r2.contains(y)) prove( Implies( premise, rsum.contains(x + y))) Model Checking 30 and two ranges, r1 and r2
  29. Copyright © SUSE x = Int('x'); y = Int('y') r1

    = Range('r1'); r2 = Range('r2') rsum = range_add(r1, r2) premise = And(r1.contains(x), r2.contains(y)) prove( Implies( premise, rsum.contains(x + y))) Model Checking 31 x can be any possible value within the r1 range and y can be any possible value within r2
  30. Copyright © SUSE x = Int('x'); y = Int('y') r1

    = Range('r1'); r2 = Range('r2') rsum = range_add(r1, r2) premise = And(r1.contains(x), r2.contains(y)) prove( Implies( premise, rsum.contains(x + y))) Model Checking 32 now if we calculate a new rsum using range_add()
  31. Copyright © SUSE x = Int('x'); y = Int('y') r1

    = Range('r1'); r2 = Range('r2') rsum = range_add(r1, r2) premise = And(r1.contains(x), r2.contains(y)) prove( Implies( premise, rsum.contains(x + y))) Model Checking 33 (x+y) should remain within rsum
  32. Copyright © SUSE © SUSE LLC. All Rights Reserved. SUSE

    and the SUSE logo are registered trademarks of SUSE LLC in the United States and other countries. All third-party trademarks are the property of their respective owners. For more information, contact SUSE at: +1 800 796 3700 (U.S./Canada) Frankenstrasse 146 90461 Nürnberg www.suse.com Thank you