Skip to content

Commit 9ab0a91

Browse files
authored
Fix concurrent map read and write in socket dataset (#21690)
This fixes a panic caused by a concurrent map read and write in Auditbeat's system/socket dataset. Fixes #21192
1 parent cf11c8b commit 9ab0a91

5 files changed

Lines changed: 39 additions & 5 deletions

File tree

CHANGELOG.next.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
195195
- auditd: Fix typo in `event.action` of `removed-user-role-from`. {pull}19300[19300]
196196
- auditd: Fix typo in `event.action` of `used-suspicious-link`. {pull}19300[19300]
197197
- system/socket: Fix kprobe grouping to allow running more than one instance. {pull}20325[20325]
198+
- system/socket: Fixed a crash due to concurrent map read and write. {issue}21192[21192] {pull}21690[21690]
198199

199200
*Filebeat*
200201

x-pack/auditbeat/module/system/socket/events.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -872,8 +872,8 @@ type execveCall struct {
872872
creds *commitCreds
873873
}
874874

875-
func (e *execveCall) getProcess() process {
876-
p := process{
875+
func (e *execveCall) getProcess() *process {
876+
p := &process{
877877
pid: e.Meta.PID,
878878
path: readCString(e.Path[:]),
879879
created: kernelTime(e.Meta.Timestamp),

x-pack/auditbeat/module/system/socket/socket_linux.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ func (m *MetricSet) Run(r mb.PushReporterV2) {
158158
} else {
159159
for _, p := range procs {
160160
if i, err := p.Info(); err == nil {
161-
process := process{
161+
process := &process{
162162
name: i.Name,
163163
pid: uint32(i.PID),
164164
args: i.Args,

x-pack/auditbeat/module/system/socket/state.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ func (f *flow) Timestamp() time.Time {
214214
}
215215

216216
type process struct {
217+
// RWMutex is used to arbitrate reads and writes to resolvedDomains.
218+
sync.RWMutex
219+
217220
pid uint32
218221
name, path string
219222
args []string
@@ -229,6 +232,8 @@ type process struct {
229232
}
230233

231234
func (p *process) addTransaction(tr dns.Transaction) {
235+
p.Lock()
236+
defer p.Unlock()
232237
if p.resolvedDomains == nil {
233238
p.resolvedDomains = make(map[string]string)
234239
}
@@ -239,6 +244,8 @@ func (p *process) addTransaction(tr dns.Transaction) {
239244

240245
// ResolveIP returns the domain associated with the given IP.
241246
func (p *process) ResolveIP(ip net.IP) (domain string, found bool) {
247+
p.RLock()
248+
defer p.RUnlock()
242249
domain, found = p.resolvedDomains[ip.String()]
243250
return
244251
}
@@ -542,13 +549,13 @@ func (s *state) ExpireOlder() {
542549
s.dns.CleanUp()
543550
}
544551

545-
func (s *state) CreateProcess(p process) error {
552+
func (s *state) CreateProcess(p *process) error {
546553
if p.pid == 0 {
547554
return errors.New("can't create process with PID 0")
548555
}
549556
s.Lock()
550557
defer s.Unlock()
551-
s.processes[p.pid] = &p
558+
s.processes[p.pid] = p
552559
if p.createdTime == (time.Time{}) {
553560
p.createdTime = s.kernTimestampToTime(p.created)
554561
}

x-pack/auditbeat/module/system/socket/state_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"fmt"
1212
"net"
1313
"os"
14+
"sync"
1415
"testing"
1516
"time"
1617

@@ -835,3 +836,28 @@ func TestSocketReuse(t *testing.T) {
835836
}
836837
assert.Len(t, flows, 1)
837838
}
839+
840+
func TestProcessDNSRace(t *testing.T) {
841+
p := new(process)
842+
var wg sync.WaitGroup
843+
wg.Add(2)
844+
address := func(i byte) net.IP { return net.IPv4(172, 16, 0, i) }
845+
go func() {
846+
for i := byte(255); i > 0; i-- {
847+
p.addTransaction(dns.Transaction{
848+
Client: net.UDPAddr{IP: net.IPv4(10, 20, 30, 40)},
849+
Server: net.UDPAddr{IP: net.IPv4(10, 20, 30, 41)},
850+
Domain: "example.net",
851+
Addresses: []net.IP{address(i)},
852+
})
853+
}
854+
wg.Done()
855+
}()
856+
go func() {
857+
for i := byte(255); i > 0; i-- {
858+
p.ResolveIP(address(i))
859+
}
860+
wg.Done()
861+
}()
862+
wg.Wait()
863+
}

0 commit comments

Comments
 (0)