seccomp: Reorder generated syscall rules for better efficiency.

This subdivides all `RuleSet`s into single-syscall rulesets, and then
classifies them depending on:

- Whether they are "trivial" or not, where "trivial" means that the syscall
  rules do not perform any verification of the syscall arguments or RIP.
- Whether they are marked "hot" or not, where "hot" means "expected to be
  frequently called".

It then orders the program as follows:

- All hot non-trivial rules go first. This makes it so that the host kernel
  can clear the syscall faster for frequently-called syscalls. These are
  checked linearly, as they tend to follow a Pareto distribution in terms of
  frequency. If they need a vsyscall check, that check is added individually.
- All cold rules go next, and form a BST. This mimics the structure of the BST
  construction that existed prior to this change.
- Lastly, all the trivial syscalls are added as a last BST.

This speeds up rule evaluation because it maximizes the use of Linux's
seccomp cache for trivial syscalls. These are therefore only ever checked
once, so they can stay at the "bottom" of the program.
All remaining (non-trivial) syscalls are ordered such that hot syscalls
are checked first, and then cold syscalls are checked with a BST.

This is a complex and security-sensitive change, but fuzz testing with full
branch coverage has shown that this has the exact same behavior as a BPF
program taken from before any of my recent seccomp/BPF changes (other than
the one adding non-negative FD checks to all `ioctl(2)` system calls).

Some benchmark results ("orig" is the state before this change):

```
                                      │     orig      │                  reordered                   │
                                      │    sec/op     │    sec/op      vs base                       │
SentrySystrap/futex                      79.44n ±  2%    73.93n ±  2%   -6.93% (n=729+722)
SentrySystrap/nanosleep                  112.3n ± 12%    107.2n ± 12%        ~ (p=0.505 n=482+477)
SentrySystrap/sendmmsg                   88.50n ±  1%    81.62n ±  1%   -7.78% (n=729+722)
SentrySystrap/fstat                      30.80n ±  2%    30.63n ±  3%        ~ (p=0.903 n=722+712)
[...]
SentrySystrap/Postgres-48                64.30n ±  5%    61.74n ±  6%   -3.97% (p=0.039 n=376+377)
```

PiperOrigin-RevId: 582808055
This commit is contained in:
Etienne Perot
2023-11-15 14:32:12 -08:00
committed by gVisor bot
parent 1ac6325b3b
commit e6979cb4d6
3 changed files with 1056 additions and 93 deletions
+1
View File
@@ -38,5 +38,6 @@ go_test(
deps = [
"//pkg/abi/linux",
"//pkg/bpf",
"@org_golang_x_sys//unix:go_default_library",
],
)
+478 -93
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff