Skip to content

Commit 2abf87f

Browse files
authored
Auditbeat: Allow multiple instances by grouping kprobes by PID (#20325)
This updates the system/socket dataset to group installed kprobes by PID instead of using a generic `auditbeat` group. This allows multiple instances of Auditbeat to run with the system/socket dataset enabled (default) avoiding collision of kprobes.
1 parent b1b7860 commit 2abf87f

2 files changed

Lines changed: 46 additions & 13 deletions

File tree

CHANGELOG.next.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
168168
- auditd: Fix spelling of anomaly in `event.category`.
169169
- auditd: Fix typo in `event.action` of `removed-user-role-from`. {pull}19300[19300]
170170
- auditd: Fix typo in `event.action` of `used-suspicious-link`. {pull}19300[19300]
171+
- system/socket: Fix kprobe grouping to allow running more than one instance. {pull}20325[20325]
171172

172173
*Filebeat*
173174

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

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ package socket
99
import (
1010
"context"
1111
"fmt"
12+
"os"
13+
"path/filepath"
1214
"sort"
1315
"strconv"
16+
"strings"
1417
"sync/atomic"
1518
"syscall"
1619
"time"
@@ -36,17 +39,18 @@ import (
3639
)
3740

3841
const (
39-
moduleName = "system"
40-
metricsetName = "socket"
41-
fullName = moduleName + "/" + metricsetName
42-
namespace = "system.audit.socket"
43-
detailSelector = metricsetName + "detailed"
44-
auditbeatGroup = "auditbeat"
42+
moduleName = "system"
43+
metricsetName = "socket"
44+
fullName = moduleName + "/" + metricsetName
45+
namespace = "system.audit.socket"
46+
detailSelector = metricsetName + "detailed"
47+
groupNamePrefix = "auditbeat_"
4548
// Magic value to detect clock-sync events generated by the metricset.
4649
clockSyncMagic uint64 = 0x42DEADBEEFABCDEF
4750
)
4851

4952
var (
53+
groupName = fmt.Sprintf("%s%d", groupNamePrefix, os.Getpid())
5054
kernelVersion string
5155
eventCount uint64
5256
)
@@ -290,7 +294,7 @@ func (m *MetricSet) Setup() (err error) {
290294
extra = WithFilterPort(22)
291295
}
292296
m.installer = newProbeInstaller(traceFS,
293-
WithGroup(auditbeatGroup),
297+
WithGroup(groupName),
294298
WithTemplates(m.templateVars),
295299
extra)
296300
defer func() {
@@ -300,10 +304,18 @@ func (m *MetricSet) Setup() (err error) {
300304
}()
301305

302306
//
303-
// remove existing KProbes from Auditbeat
307+
// remove dangling KProbes from terminated Auditbeat processes.
308+
// Not a fatal error if they can't be removed.
304309
//
305-
if err = m.installer.UninstallIf(isOwnProbe); err != nil {
306-
return errors.Wrap(err, "unable to delete existing KProbes. Is Auditbeat already running?")
310+
if err = m.installer.UninstallIf(isDeadAuditbeat); err != nil {
311+
m.log.Debugf("Removing existing probes from terminated instances: %+v", err)
312+
}
313+
314+
//
315+
// remove existing Auditbeat KProbes that match the current PID.
316+
//
317+
if err = m.installer.UninstallIf(isThisAuditbeat); err != nil {
318+
return errors.Wrapf(err, "unable to delete existing KProbes for group %s", groupName)
307319
}
308320

309321
//
@@ -409,7 +421,7 @@ func (m *MetricSet) Cleanup() {
409421
}
410422
}
411423
if m.installer != nil {
412-
if err := m.installer.UninstallIf(isOwnProbe); err != nil {
424+
if err := m.installer.UninstallIf(isThisAuditbeat); err != nil {
413425
m.log.Warnf("Failed to remove KProbes on exit: %v", err)
414426
}
415427
}
@@ -468,8 +480,28 @@ func triggerClockSync() {
468480
unix.Uname(&buf)
469481
}
470482

471-
func isOwnProbe(probe tracing.Probe) bool {
472-
return probe.Group == auditbeatGroup
483+
func isRunningAuditbeat(pid int) bool {
484+
path := fmt.Sprintf("/proc/%d/exe", pid)
485+
exePath, err := os.Readlink(path)
486+
if err != nil {
487+
// Not a running process
488+
return false
489+
}
490+
exeName := filepath.Base(exePath)
491+
return strings.HasPrefix(exeName, "auditbeat")
492+
}
493+
494+
func isDeadAuditbeat(probe tracing.Probe) bool {
495+
if strings.HasPrefix(probe.Group, groupNamePrefix) && probe.Group != groupName {
496+
if pid, err := strconv.Atoi(probe.Group[len(groupNamePrefix):]); err == nil && !isRunningAuditbeat(pid) {
497+
return true
498+
}
499+
}
500+
return false
501+
}
502+
503+
func isThisAuditbeat(probe tracing.Probe) bool {
504+
return probe.Group == groupName
473505
}
474506

475507
type mountPoint struct {

0 commit comments

Comments
 (0)