Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add_process_metadata: Support different integer types for pid field #26829

Merged
merged 5 commits into from Jul 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Expand Up @@ -243,6 +243,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
- Omit full index template from errors that occur while loading the template. {pull}25743[25743]
- In the script processor, the `decode_xml` and `decode_xml_wineventlog` processors are now available as `DecodeXML` and `DecodeXMLWineventlog` respectively.
- Fix encoding errors when using the disk queue on nested data with multi-byte characters {pull}26484[26484]
- Fix `add_process_metadata` processor complaining about valid pid fields not being valid integers. {pull}26829[26829] {issue}26830[26830]

*Auditbeat*

Expand Down
38 changes: 28 additions & 10 deletions libbeat/processors/add_process_metadata/add_process_metadata.go
Expand Up @@ -19,6 +19,7 @@ package add_process_metadata

import (
"fmt"
"reflect"
"strconv"
"time"

Expand Down Expand Up @@ -182,23 +183,40 @@ func (p *addProcessMetadata) Run(event *beat.Event) (*beat.Event, error) {
return event, ErrNoMatch
}

func (p *addProcessMetadata) enrich(event common.MapStr, pidField string) (result common.MapStr, err error) {
pidIf, err := event.GetValue(pidField)
if err != nil {
return nil, err
}

var pid int
switch v := pidIf.(type) {
func pidToInt(value interface{}) (pid int, err error) {
switch v := value.(type) {
case string:
pid, err = strconv.Atoi(v)
if err != nil {
return nil, errors.Wrapf(err, "cannot convert string field '%s' to an integer", pidField)
return 0, errors.Wrap(err, "error converting string to integer")
}
case int:
pid = v
case int8, int16, int32, int64:
pid64 := reflect.ValueOf(v).Int()
if pid = int(pid64); int64(pid) != pid64 {
return 0, errors.Errorf("integer out of range: %d", pid64)
}
case uint, uintptr, uint8, uint16, uint32, uint64:
pidu64 := reflect.ValueOf(v).Uint()
if pid = int(pidu64); pid < 0 || uint64(pid) != pidu64 {
return 0, errors.Errorf("integer out of range: %d", pidu64)
}
default:
return nil, errors.Errorf("cannot parse field '%s' (not an integer or string)", pidField)
return 0, errors.Errorf("not an integer or string, but %T", v)
}
return pid, nil
}

func (p *addProcessMetadata) enrich(event common.MapStr, pidField string) (result common.MapStr, err error) {
pidIf, err := event.GetValue(pidField)
if err != nil {
return nil, err
}

pid, err := pidToInt(pidIf)
if err != nil {
return nil, errors.Wrapf(err, "cannot parse pid field '%s'", pidField)
}

var meta common.MapStr
Expand Down
160 changes: 158 additions & 2 deletions libbeat/processors/add_process_metadata/add_process_metadata_test.go
Expand Up @@ -18,9 +18,11 @@
package add_process_metadata

import (
"math"
"os"
"testing"
"time"
"unsafe"

"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -403,7 +405,7 @@ func TestAddProcessMetadata(t *testing.T) {
expected: common.MapStr{
"ppid": "a",
},
err: errors.New("error applying add_process_metadata processor: cannot convert string field 'ppid' to an integer: strconv.Atoi: parsing \"a\": invalid syntax"),
err: errors.New("error applying add_process_metadata processor: cannot parse pid field 'ppid': error converting string to integer: strconv.Atoi: parsing \"a\": invalid syntax"),
},
{
description: "bad PID field type",
Expand All @@ -416,7 +418,7 @@ func TestAddProcessMetadata(t *testing.T) {
expected: common.MapStr{
"ppid": false,
},
err: errors.New("error applying add_process_metadata processor: cannot parse field 'ppid' (not an integer or string)"),
err: errors.New("error applying add_process_metadata processor: cannot parse pid field 'ppid': not an integer or string, but bool"),
},
{
description: "process not found",
Expand Down Expand Up @@ -824,3 +826,157 @@ func TestBadProcess(t *testing.T) {
assert.NotNil(t, result.Fields)
assert.Equal(t, ev.Fields, result.Fields)
}

func TestPIDToInt(t *testing.T) {
const intIs64bit = unsafe.Sizeof(int(0)) == unsafe.Sizeof(int64(0))
for _, test := range []struct {
name string
pid interface{}
fail bool
}{
{
name: "numeric string",
pid: "1234",
},
{
name: "numeric string ignore octal",
pid: "008",
},
{
name: "numeric string invalid hex",
pid: "0x10",
fail: true,
},
{
name: "non-numeric string",
pid: "abcd",
fail: true,
},
{
name: "int",
pid: 0,
},
{
name: "int min",
pid: math.MaxInt32,
},
{
name: "int max",
pid: math.MaxInt32,
},
{
name: "uint min",
pid: uint(0),
},
{
name: "uint max",
pid: uint(math.MaxUint32),
fail: !intIs64bit,
},
{
name: "int8",
pid: int8(0),
},
{
name: "int8 min",
pid: int8(math.MinInt8),
},
{
name: "int8 max",
pid: int8(math.MaxInt8),
},
{
name: "uint8 min",
pid: uint8(0),
},
{
name: "uint8 max",
pid: uint8(math.MaxUint8),
},
{
name: "int16",
pid: int16(0),
},
{
name: "int16 min",
pid: int16(math.MinInt16),
},
{
name: "int16 max",
pid: int16(math.MaxInt16),
},
{
name: "uint16 min",
pid: uint16(0),
},
{
name: "uint16 max",
pid: uint16(math.MaxUint16),
},
{
name: "int32",
pid: int32(0),
},
{
name: "int32 min",
pid: int32(math.MinInt32),
},
{
name: "int32 max",
pid: int32(math.MaxInt32),
},
{
name: "uint32 min",
pid: uint32(0),
},
{
name: "uint32 max",
pid: uint32(math.MaxUint32),
fail: !intIs64bit,
},
{
name: "int64",
pid: int64(0),
fail: false,
},
{
name: "int64 min",
pid: int64(math.MinInt64),
fail: !intIs64bit,
},
{
name: "int64 max",
pid: int64(math.MaxInt64),
fail: !intIs64bit,
},
{
name: "uint64 min",
pid: uint64(0),
fail: false,
},
{
name: "uint64 max",
pid: uint64(math.MaxUint64),
fail: true,
},
{
name: "uintptr",
pid: uintptr(0),
fail: false,
},
{
name: "boolean",
pid: false,
fail: true,
},
} {
t.Run(test.name, func(t *testing.T) {
_, err := pidToInt(test.pid)
if test.fail {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}