bpf: Use optimizer for seccomp-bpf programs.

This speeds up:

- The Sentry and the Gofer's seccomp-bpf programs
- User application seccomp-bpf programs
- Systrap and ptrace seccomp-bpf rules

Some benchmark results with Postgres:

```
                                   │    before     │                    opt                    │
                                   │    sec/op     │    sec/op     vs base                     │
SentrySystrap/Postgres/futex          88.82n ±  2%   81.29n ±  2%   -8.48% (p=0.000 n=519+510)
SentrySystrap/Postgres/nanosleep      116.9n ± 19%   115.9n ± 17%        ~ (p=0.859 n=350+317)
SentrySystrap/Postgres/sendmmsg       88.68n ±  1%   81.56n ±  1%   -8.04% (n=519+510)
SentrySystrap/Postgres/fstat          24.47n ±  3%   24.31n ±  6%        ~ (p=0.832 n=514+502)
[...]
SentrySystrap/Postgres-48             71.00n ±  8%   63.00n ±  6%  -11.27% (p=0.002 n=183+181)
```

PiperOrigin-RevId: 570931073
This commit is contained in:
Etienne Perot
2023-10-05 00:51:48 -07:00
committed by gVisor bot
parent 9ff4c45938
commit 09be6cec5e
3 changed files with 25 additions and 4 deletions
+3 -3
View File
@@ -97,8 +97,8 @@ func (p Program) Length() int {
return len(p.instructions)
}
// Compile performs validation on a sequence of BPF instructions before
// wrapping them in a Program.
// Compile performs validation and optimization on a sequence of BPF
// instructions before wrapping them in a Program.
func Compile(insns []Instruction) (Program, error) {
if len(insns) == 0 || len(insns) > MaxInstructions {
return Program{}, Error{InvalidInstructionCount, len(insns)}
@@ -214,7 +214,7 @@ func Compile(insns []Instruction) (Program, error) {
}
}
return Program{insns}, nil
return Program{Optimize(insns)}, nil
}
// Input represents a source of input data for a BPF program. (BPF
+13
View File
@@ -705,6 +705,19 @@ func TestValidInstructions(t *testing.T) {
},
expectedRet: 2,
},
{
desc: "Optimizable program",
insns: []Instruction{
Stmt(Ld|Imm|W, 42), // A = 42
Jump(Jmp|Jeq|K, 42, 0, 1), // if (A == 42) jmp 0 else 1
Jump(Jmp|Ja, 1, 0, 0), // jmp 1
Jump(Jmp|Ja, 2, 0, 0), // jmp 2
Stmt(Ld|Imm|W, 37), // A = 37
Stmt(Ret|K, 0), // return 0
Stmt(Ret|K, 1), // return 1
},
expectedRet: 0,
},
} {
p, err := Compile(test.insns)
if err != nil {
+9 -1
View File
@@ -152,7 +152,15 @@ func BuildProgram(rules []RuleSet, defaultAction, badArchAction linux.BPFAction)
}
program.AddStmt(bpf.Ret|bpf.K, uint32(defaultAction))
return program.Instructions()
insns, err := program.Instructions()
if err != nil {
return insns, err
}
beforeOpt := len(insns)
insns = bpf.Optimize(insns)
afterOpt := len(insns)
log.Debugf("Seccomp program optimized from %d to %d instructions", beforeOpt, afterOpt)
return insns, nil
}
// buildIndex builds a BST to quickly search through all syscalls.