seccomp: Make SyscallRules.Copy do a deep copy.

This adds a `Copy` function to the `SyscallRule` interface, so that syscall
rules can be deeply copied.

This is useful in the context of precompiled rules, which can be precompiled
in parallel and where some optimizers will modify the `SyscallRule` objects
themselves (e.g. removing the `MatchAll` rules from an `Or` rule). When this
happens in parallel, this causes a race of two goroutines writing to the same
slice when the rules are based on a similar source.
Each goroutine should be dealing with its own set of rules, hence making
`Copy` a deep copy.

PiperOrigin-RevId: 584169637
This commit is contained in:
Etienne Perot
2023-11-20 17:25:50 -08:00
committed by gVisor bot
parent 9c6f50d59e
commit f221e212aa
+30 -4
View File
@@ -488,6 +488,9 @@ type SyscallRule interface {
// next into the program.
Render(program *syscallProgram, labelSet *labelSet)
// Copy returns a copy of this `SyscallRule`.
Copy() SyscallRule
// Recurse should call the given function on all `SyscallRule`s that are
// part of this `SyscallRule`, and should replace them with the returned
// `SyscallRule`. For example, conjunctive rules should call the given
@@ -507,6 +510,11 @@ func (MatchAll) Render(program *syscallProgram, labelSet *labelSet) {
program.JumpTo(labelSet.Matched())
}
// Copy implements `SyscallRule.Copy`.
func (MatchAll) Copy() SyscallRule {
return MatchAll{}
}
// Recurse implements `SyscallRule.Recurse`.
func (MatchAll) Recurse(func(SyscallRule) SyscallRule) {}
@@ -534,6 +542,15 @@ func (or Or) Render(program *syscallProgram, labelSet *labelSet) {
program.JumpTo(labelSet.Mismatched())
}
// Copy implements `SyscallRule.Copy`.
func (or Or) Copy() SyscallRule {
orCopy := make([]SyscallRule, len(or))
for i, rule := range or {
orCopy[i] = rule.Copy()
}
return Or(orCopy)
}
// Recurse implements `SyscallRule.Recurse`.
func (or Or) Recurse(fn func(SyscallRule) SyscallRule) {
for i, rule := range or {
@@ -583,6 +600,15 @@ func (and And) Render(program *syscallProgram, labelSet *labelSet) {
program.JumpTo(labelSet.Matched())
}
// Copy implements `SyscallRule.Copy`.
func (and And) Copy() SyscallRule {
andCopy := make([]SyscallRule, len(and))
for i, rule := range and {
andCopy[i] = rule.Copy()
}
return And(andCopy)
}
// Recurse implements `SyscallRule.Recurse`.
func (and And) Recurse(fn func(SyscallRule) SyscallRule) {
for i, rule := range and {
@@ -624,8 +650,8 @@ type PerArg [7]ValueMatcher // 6 arguments + RIP
// instruction pointer.
const RuleIP = 6
// clone returns a copy of this `PerArg`.
func (pa PerArg) clone() PerArg {
// Copy implements `SyscallRule.Copy`.
func (pa PerArg) Copy() SyscallRule {
return PerArg{
pa[0],
pa[1],
@@ -829,11 +855,11 @@ func (sr SyscallRules) Merge(other SyscallRules) SyscallRules {
return sr
}
// Copy returns a copy of these SyscallRules.
// Copy returns a deep copy of these SyscallRules.
func (sr SyscallRules) Copy() SyscallRules {
rulesCopy := make(map[uintptr]SyscallRule, len(sr.rules))
for sysno, r := range sr.rules {
rulesCopy[sysno] = r
rulesCopy[sysno] = r.Copy()
}
return MakeSyscallRules(rulesCopy)
}