Skip to content

Commit

Permalink
Auditbeat: Allow multiple instances by grouping kprobes by PID (elast…
Browse files Browse the repository at this point in the history
…ic#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.

(cherry picked from commit 2abf87f)
  • Loading branch information
adriansr committed Jul 30, 2020
1 parent 51cd70e commit bcb6cc2
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 @@ -100,6 +100,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
- system/socket: Fixed compatibility issue with kernel 5.x. {pull}15771[15771]
- system/package: Fix parsing of Installed-Size field of DEB packages. {issue}16661[16661] {pull}17188[17188]
- system module: Fix panic during initialisation when /proc/stat can't be read. {pull}17569[17569]
- 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 bcb6cc2

Please sign in to comment.