Skip to content

Commit

Permalink
Auditbeat: Allow multiple instances by grouping kprobes by PID (#20325)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
adriansr authored Jul 30, 2020
1 parent b1b7860 commit 2abf87f
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
- auditd: Fix spelling of anomaly in `event.category`.
- auditd: Fix typo in `event.action` of `removed-user-role-from`. {pull}19300[19300]
- auditd: Fix typo in `event.action` of `used-suspicious-link`. {pull}19300[19300]
- system/socket: Fix kprobe grouping to allow running more than one instance. {pull}20325[20325]

*Filebeat*

Expand Down
58 changes: 45 additions & 13 deletions x-pack/auditbeat/module/system/socket/socket_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ package socket
import (
"context"
"fmt"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"sync/atomic"
"syscall"
"time"
Expand All @@ -36,17 +39,18 @@ import (
)

const (
moduleName = "system"
metricsetName = "socket"
fullName = moduleName + "/" + metricsetName
namespace = "system.audit.socket"
detailSelector = metricsetName + "detailed"
auditbeatGroup = "auditbeat"
moduleName = "system"
metricsetName = "socket"
fullName = moduleName + "/" + metricsetName
namespace = "system.audit.socket"
detailSelector = metricsetName + "detailed"
groupNamePrefix = "auditbeat_"
// Magic value to detect clock-sync events generated by the metricset.
clockSyncMagic uint64 = 0x42DEADBEEFABCDEF
)

var (
groupName = fmt.Sprintf("%s%d", groupNamePrefix, os.Getpid())
kernelVersion string
eventCount uint64
)
Expand Down Expand Up @@ -290,7 +294,7 @@ func (m *MetricSet) Setup() (err error) {
extra = WithFilterPort(22)
}
m.installer = newProbeInstaller(traceFS,
WithGroup(auditbeatGroup),
WithGroup(groupName),
WithTemplates(m.templateVars),
extra)
defer func() {
Expand All @@ -300,10 +304,18 @@ func (m *MetricSet) Setup() (err error) {
}()

//
// remove existing KProbes from Auditbeat
// remove dangling KProbes from terminated Auditbeat processes.
// Not a fatal error if they can't be removed.
//
if err = m.installer.UninstallIf(isOwnProbe); err != nil {
return errors.Wrap(err, "unable to delete existing KProbes. Is Auditbeat already running?")
if err = m.installer.UninstallIf(isDeadAuditbeat); err != nil {
m.log.Debugf("Removing existing probes from terminated instances: %+v", err)
}

//
// remove existing Auditbeat KProbes that match the current PID.
//
if err = m.installer.UninstallIf(isThisAuditbeat); err != nil {
return errors.Wrapf(err, "unable to delete existing KProbes for group %s", groupName)
}

//
Expand Down Expand Up @@ -409,7 +421,7 @@ func (m *MetricSet) Cleanup() {
}
}
if m.installer != nil {
if err := m.installer.UninstallIf(isOwnProbe); err != nil {
if err := m.installer.UninstallIf(isThisAuditbeat); err != nil {
m.log.Warnf("Failed to remove KProbes on exit: %v", err)
}
}
Expand Down Expand Up @@ -468,8 +480,28 @@ func triggerClockSync() {
unix.Uname(&buf)
}

func isOwnProbe(probe tracing.Probe) bool {
return probe.Group == auditbeatGroup
func isRunningAuditbeat(pid int) bool {
path := fmt.Sprintf("/proc/%d/exe", pid)
exePath, err := os.Readlink(path)
if err != nil {
// Not a running process
return false
}
exeName := filepath.Base(exePath)
return strings.HasPrefix(exeName, "auditbeat")
}

func isDeadAuditbeat(probe tracing.Probe) bool {
if strings.HasPrefix(probe.Group, groupNamePrefix) && probe.Group != groupName {
if pid, err := strconv.Atoi(probe.Group[len(groupNamePrefix):]); err == nil && !isRunningAuditbeat(pid) {
return true
}
}
return false
}

func isThisAuditbeat(probe tracing.Probe) bool {
return probe.Group == groupName
}

type mountPoint struct {
Expand Down

0 comments on commit 2abf87f

Please sign in to comment.