From f221e212aabb4271d4b255fa273e3305fd9a5dd1 Mon Sep 17 00:00:00 2001 From: Etienne Perot Date: Mon, 20 Nov 2023 17:23:12 -0800 Subject: [PATCH] `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 --- pkg/seccomp/seccomp_rules.go | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/pkg/seccomp/seccomp_rules.go b/pkg/seccomp/seccomp_rules.go index 3b6c17080..38f0dda58 100644 --- a/pkg/seccomp/seccomp_rules.go +++ b/pkg/seccomp/seccomp_rules.go @@ -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) }