mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Fix recursive read lock taken on TaskSet
SyncSyscallFiltersToThreadGroup and Task.TheadID() both acquired TaskSet RWLock in R mode and could deadlock if a writer comes in between. PiperOrigin-RevId: 222313551 Change-Id: I4221057d8d46fec544cbfa55765c9a284fe7ebfa
This commit is contained in:
committed by
Shentubot
parent
03c1eb78b5
commit
8b314b0bf4
@@ -179,20 +179,19 @@ func (t *Task) evaluateSyscallFilters(sysno int32, args arch.SyscallArguments, i
|
||||
// AppendSyscallFilter adds BPF program p as a system call filter.
|
||||
//
|
||||
// Preconditions: The caller must be running on the task goroutine.
|
||||
func (t *Task) AppendSyscallFilter(p bpf.Program) error {
|
||||
func (t *Task) AppendSyscallFilter(p bpf.Program, syncAll bool) error {
|
||||
// While syscallFilters are an atomic.Value we must take the mutex to prevent
|
||||
// our read-copy-update from happening while another task is syncing syscall
|
||||
// filters to us, this keeps the filters in a consistent state.
|
||||
t.tg.signalHandlers.mu.Lock()
|
||||
defer t.tg.signalHandlers.mu.Unlock()
|
||||
|
||||
// Cap the combined length of all syscall filters (plus a penalty of 4
|
||||
// instructions per filter beyond the first) to
|
||||
// maxSyscallFilterInstructions. (This restriction is inherited from
|
||||
// Linux.)
|
||||
// instructions per filter beyond the first) to maxSyscallFilterInstructions.
|
||||
// This restriction is inherited from Linux.
|
||||
totalLength := p.Length()
|
||||
var newFilters []bpf.Program
|
||||
|
||||
// While syscallFilters are an atomic.Value we must take the mutex to
|
||||
// prevent our read-copy-update from happening while another task
|
||||
// is syncing syscall filters to us, this keeps the filters in a
|
||||
// consistent state.
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
if sf := t.syscallFilters.Load(); sf != nil {
|
||||
oldFilters := sf.([]bpf.Program)
|
||||
for _, f := range oldFilters {
|
||||
@@ -207,31 +206,18 @@ func (t *Task) AppendSyscallFilter(p bpf.Program) error {
|
||||
|
||||
newFilters = append(newFilters, p)
|
||||
t.syscallFilters.Store(newFilters)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SyncSyscallFiltersToThreadGroup will copy this task's filters to all other
|
||||
// threads in our thread group.
|
||||
func (t *Task) SyncSyscallFiltersToThreadGroup() error {
|
||||
f := t.syscallFilters.Load()
|
||||
|
||||
t.tg.pidns.owner.mu.RLock()
|
||||
defer t.tg.pidns.owner.mu.RUnlock()
|
||||
|
||||
// Note: No new privs is always assumed to be set.
|
||||
for ot := t.tg.tasks.Front(); ot != nil; ot = ot.Next() {
|
||||
if ot.ThreadID() != t.ThreadID() {
|
||||
// We must take the other task's mutex to prevent it from
|
||||
// appending to its own syscall filters while we're syncing.
|
||||
ot.mu.Lock()
|
||||
var copiedFilters []bpf.Program
|
||||
if f != nil {
|
||||
copiedFilters = append(copiedFilters, f.([]bpf.Program)...)
|
||||
if syncAll {
|
||||
// Note: No new privs is always assumed to be set.
|
||||
for ot := t.tg.tasks.Front(); ot != nil; ot = ot.Next() {
|
||||
if ot != t {
|
||||
var copiedFilters []bpf.Program
|
||||
copiedFilters = append(copiedFilters, newFilters...)
|
||||
ot.syscallFilters.Store(copiedFilters)
|
||||
}
|
||||
ot.syscallFilters.Store(copiedFilters)
|
||||
ot.mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -392,7 +392,7 @@ type Task struct {
|
||||
|
||||
// syscallFilters is all seccomp-bpf syscall filters applicable to the
|
||||
// task, in the order in which they were installed. The type of the atomic
|
||||
// is []bpf.Program. Writing needs to be protected by mu.
|
||||
// is []bpf.Program. Writing needs to be protected by the signal mutex.
|
||||
//
|
||||
// syscallFilters is owned by the task goroutine.
|
||||
syscallFilters atomic.Value `state:".([]bpf.Program)"`
|
||||
|
||||
@@ -68,12 +68,7 @@ func seccomp(t *kernel.Task, mode, flags uint64, addr usermem.Addr) error {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
|
||||
err = t.AppendSyscallFilter(compiledFilter)
|
||||
if err == nil && tsync {
|
||||
// Now we must copy this seccomp program to all other threads.
|
||||
err = t.SyncSyscallFiltersToThreadGroup()
|
||||
}
|
||||
return err
|
||||
return t.AppendSyscallFilter(compiledFilter, tsync)
|
||||
}
|
||||
|
||||
// Seccomp implements linux syscall seccomp(2).
|
||||
|
||||
Reference in New Issue
Block a user