Skip to content

Commit

Permalink
x-pack/auditbeat/module/system/socket: get full length path and arg f…
Browse files Browse the repository at this point in the history
…rom /proc when not available from kprobe (#29410) (#29958)

Also use first arg from sysinfo.Processes in place of Name to avoid process name
truncation.

(cherry picked from commit d46bb5f)

Co-authored-by: Dan Kortschak <[email protected]>
  • Loading branch information
mergify[bot] and efd6 authored Jan 24, 2022
1 parent 05a46ac commit cd16c9f
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 17 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
*Auditbeat*

- system/socket: Fix startup errors on newer 5.x kernels due to missing _do_fork function. {issue}29607[29607] {pull}29744[29744]
- 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/package: Fix an error that can occur while trying to persist package metadata. {issue}18536[18536] {pull}18887[18887]
- system/socket: Fix bugs leading to wrong process being attributed to flows. {pull}29166[29166] {issue}17165[17165]
- system/socket: Fix process name and arg truncation for long names, paths and args lists. {issue}24667[24667] {pull}29410[29410]

*Filebeat*

Expand Down
76 changes: 59 additions & 17 deletions x-pack/auditbeat/module/system/socket/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -859,8 +859,10 @@ func (e *inetReleaseCall) Update(s *state) error {
// kernels it needs to dump fixed-size arrays in 8-byte chunks. As the total
// number of fetchargs available is limited, we have to dump only the first
// 128 bytes of every argument.
const maxProgArgLen = 128
const maxProgArgs = 5
const (
maxProgArgLen = 128
maxProgArgs = 5
)

type execveCall struct {
Meta tracing.Metadata `kprobe:"metadata"`
Expand All @@ -880,38 +882,78 @@ type execveCall struct {
func (e *execveCall) getProcess() *process {
p := &process{
pid: e.Meta.PID,
path: readCString(e.Path[:]),
created: kernelTime(e.Meta.Timestamp),
}
p.name = filepath.Base(p.path)
var argc int
for argc = 0; argc <= maxProgArgs; argc++ {
if e.Ptrs[argc] == 0 {
break

if idx := bytes.IndexByte(e.Path[:], 0); idx >= 0 {
// Fast path if we already have the path.
p.path = string(e.Path[:idx])
} else {
// Attempt to get the path from the /prox/<pid>/exe symlink.
var err error
p.path, err = filepath.EvalSymlinks(fmt.Sprintf("/proc/%d/exe", e.Meta.PID))
if err != nil {
if pe, ok := err.(*os.PathError); ok && strings.Contains(pe.Path, "(deleted)") {
// Keep the deleted path from the PathError.
p.path = pe.Path
} else {
// Fallback to the truncated path.
p.path = string(e.Path[:]) + " ..."
}
}
}
p.args = make([]string, argc)
params := [maxProgArgs][]byte{

// Check for truncation of arg list or arguments.
params := [...][]byte{
e.Param0[:],
e.Param1[:],
e.Param2[:],
e.Param3[:],
e.Param4[:],
}
limit := argc
if limit > maxProgArgs {
limit = maxProgArgs
p.args[limit] = "..."
var (
argc int
truncatedArg bool
)
for argc = 0; argc < len(e.Ptrs); argc++ {
if e.Ptrs[argc] == 0 {
break
}
if argc < len(params) && bytes.IndexByte(params[argc], 0) < 0 {
truncatedArg = true
}
}
if argc > maxProgArgs || truncatedArg {
// Attempt to get complete args list from /proc/<pid>/cmdline.
cmdline, err := os.ReadFile(fmt.Sprintf("/proc/%d/cmdline", e.Meta.PID))
if err == nil {
p.args = strings.Split(strings.TrimRight(string(cmdline), "\x00"), "\x00")
}
}
for i := 0; i < limit; i++ {
p.args[i] = readCString(params[i])

if p.args == nil {
// Fallback to arg list if unsuccessful or no truncation.
p.args = make([]string, argc)
if argc > maxProgArgs {
argc = maxProgArgs
p.args[argc] = "..."
}
for i, par := range params[:argc] {
p.args[i] = readCString(par)
}
}
if p.hasCreds = e.creds != nil; p.hasCreds {

// Get name from first argument.
p.name = filepath.Base(p.args[0])

if e.creds != nil {
p.hasCreds = true
p.uid = e.creds.UID
p.gid = e.creds.GID
p.euid = e.creds.EUID
p.egid = e.creds.EGID
}

return p
}

Expand Down
9 changes: 9 additions & 0 deletions x-pack/auditbeat/module/system/socket/socket_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,15 @@ func (m *MetricSet) Run(r mb.PushReporterV2) {
} else {
for _, p := range procs {
if i, err := p.Info(); err == nil {
if len(i.Name) == 16 && len(i.Args) != 0 {
// github.com/prometheus/procfs uses /proc/<pid>/stat for
// the process name which is truncated to 16 bytes, so get
// the name from the cmdline data if it might be truncated.
// The guard for length of i.Args is for cases where there
// is no command line reported by proc fs; this should never
// happen, but does.
i.Name = filepath.Base(i.Args[0])
}
process := &process{
name: i.Name,
pid: uint32(i.PID),
Expand Down

0 comments on commit cd16c9f

Please sign in to comment.