Skip to content

Commit

Permalink
pkg/events: fix socket option parse args edge cases (aquasecurity#2157)
Browse files Browse the repository at this point in the history
libbpf go currently parse the socket option argument in some cases to
include "or" in the middle between to consts names.
The reason is that the kernel has 2 consts with the same name.
According to the context we know which constant is relevant.
This PR fix the parsed option name to be the one we expect it to be.
  • Loading branch information
AlonZivony authored Sep 12, 2022
1 parent 719295b commit 4b94f4b
Show file tree
Hide file tree
Showing 2 changed files with 237 additions and 2 deletions.
51 changes: 49 additions & 2 deletions pkg/events/parse_args.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ func ParseArgs(event *trace.Event) error {
ParseOrEmptyString(modeArg, inodeModeArgument, err)
}
}
case SecuritySocketSetsockopt, Setsockopt, Getsockopt:
case SecuritySocketSetsockopt, Setsockopt:
if levelArg := GetArg(event, "level"); levelArg != nil {
if level, isInt := levelArg.Value.(int32); isInt {
levelArgument, err := helpers.ParseSocketLevel(uint64(level))
Expand All @@ -208,7 +208,37 @@ func ParseArgs(event *trace.Event) error {
if optionNameArg := GetArg(event, "optname"); optionNameArg != nil {
if opt, isInt := optionNameArg.Value.(int32); isInt {
optionNameArgument, err := helpers.ParseSocketOption(uint64(opt))
ParseOrEmptyString(optionNameArg, optionNameArgument, err)
customString, ok := setSocketOptionsCustomNamesMap[optionNameArgument.Value()]
if err == nil && ok {
customArgument := CustomFunctionArgument{
val: optionNameArgument.Value(),
str: customString,
}
ParseOrEmptyString(optionNameArg, customArgument, err)
} else {
ParseOrEmptyString(optionNameArg, optionNameArgument, err)
}
}
}
case Getsockopt:
if levelArg := GetArg(event, "level"); levelArg != nil {
if level, isInt := levelArg.Value.(int32); isInt {
levelArgument, err := helpers.ParseSocketLevel(uint64(level))
ParseOrEmptyString(levelArg, levelArgument, err)
}
}
if optionNameArg := GetArg(event, "optname"); optionNameArg != nil {
if opt, isInt := optionNameArg.Value.(int32); isInt {
optionNameArgument, err := helpers.ParseSocketOption(uint64(opt))
if err == nil && optionNameArgument.Value() == helpers.SO_ATTACH_OR_GET_FILTER.Value() {
customArgument := CustomFunctionArgument{
val: optionNameArgument.Value(),
str: "SO_GET_FILTER",
}
ParseOrEmptyString(optionNameArg, customArgument, err)
} else {
ParseOrEmptyString(optionNameArg, optionNameArgument, err)
}
}
}
}
Expand Down Expand Up @@ -302,3 +332,20 @@ func parseKernelReadFileId(id int32) (string, error) {
}
return kernelReadFileIdStr, nil
}

var setSocketOptionsCustomNamesMap = map[uint64]string{
helpers.SO_ATTACH_OR_GET_FILTER.Value(): "SO_ATTACH_FILTER",
helpers.SO_DETACH_FILTER_OR_BPF.Value(): "SO_DETACH_FILTER",
}

type CustomFunctionArgument struct {
val uint64
str string
}

func (arg CustomFunctionArgument) String() string {
return arg.str
}
func (arg CustomFunctionArgument) Value() uint64 {
return arg.val
}
188 changes: 188 additions & 0 deletions pkg/events/parse_args_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package events

import (
"github.com/aquasecurity/libbpfgo/helpers"
"github.com/aquasecurity/tracee/types/trace"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
)

func TestParseArgs(t *testing.T) {
t.Run("Parse setsockopt value", func(t *testing.T) {
testCases := []struct {
name string
args []trace.Argument
expectedArgs []trace.Argument
}{
{
name: "normal flow",
args: []trace.Argument{
{
ArgMeta: trace.ArgMeta{
Name: "optname",
Type: "int",
},
Value: int32(helpers.SO_LOCK_FILTER.Value()),
},
{
ArgMeta: trace.ArgMeta{
Name: "level",
Type: "int",
},
Value: int32(helpers.SOL_IP.Value()),
},
},
expectedArgs: []trace.Argument{
{
ArgMeta: trace.ArgMeta{
Name: "optname",
Type: "string",
},
Value: helpers.SO_LOCK_FILTER.String(),
},
{
ArgMeta: trace.ArgMeta{
Name: "level",
Type: "string",
},
Value: helpers.SOL_IP.String(),
},
},
},
{
name: "SO_ATTACH_FILTER optname",
args: []trace.Argument{
{
ArgMeta: trace.ArgMeta{
Name: "optname",
Type: "int",
},
Value: int32(helpers.SO_ATTACH_OR_GET_FILTER.Value()),
},
},
expectedArgs: []trace.Argument{
{
ArgMeta: trace.ArgMeta{
Name: "optname",
Type: "string",
},
Value: "SO_ATTACH_FILTER",
},
},
},
{
name: "normal optname",
args: []trace.Argument{
{
ArgMeta: trace.ArgMeta{
Name: "optname",
Type: "int",
},
Value: int32(helpers.SO_LOCK_FILTER.Value()),
},
},
expectedArgs: []trace.Argument{
{
ArgMeta: trace.ArgMeta{
Name: "optname",
Type: "string",
},
Value: helpers.SO_LOCK_FILTER.String(),
},
},
},
}

for _, testCase := range testCases {
event := trace.Event{
EventID: int(Setsockopt),
Args: testCase.args,
}
err := ParseArgs(&event)
require.NoError(t, err)
for _, expArg := range testCase.expectedArgs {
arg := GetArg(&event, expArg.Name)
assert.Equal(t, expArg, *arg)
}
}
})

t.Run("Parse getsockopt value", func(t *testing.T) {
testCases := []struct {
name string
args []trace.Argument
expectedArgs []trace.Argument
}{
{
name: "normal optname",
args: []trace.Argument{
{
ArgMeta: trace.ArgMeta{
Name: "optname",
Type: "int",
},
Value: int32(helpers.SO_LOCK_FILTER.Value()),
},
{
ArgMeta: trace.ArgMeta{
Name: "level",
Type: "int",
},
Value: int32(helpers.SOL_IP.Value()),
},
},
expectedArgs: []trace.Argument{
{
ArgMeta: trace.ArgMeta{
Name: "optname",
Type: "string",
},
Value: helpers.SO_LOCK_FILTER.String(),
},
{
ArgMeta: trace.ArgMeta{
Name: "level",
Type: "string",
},
Value: helpers.SOL_IP.String(),
},
},
},
{
name: "SO_GET_FILTER optname",
args: []trace.Argument{
{
ArgMeta: trace.ArgMeta{
Name: "optname",
Type: "int",
},
Value: int32(helpers.SO_ATTACH_OR_GET_FILTER.Value()),
},
},
expectedArgs: []trace.Argument{
{
ArgMeta: trace.ArgMeta{
Name: "optname",
Type: "string",
},
Value: "SO_GET_FILTER",
},
},
},
}

for _, testCase := range testCases {
event := &trace.Event{
EventID: int(Getsockopt),
Args: testCase.args,
}
err := ParseArgs(event)
require.NoError(t, err)
for _, expArg := range testCase.expectedArgs {
arg := GetArg(event, expArg.Name)
assert.Equal(t, expArg, *arg)
}
}
})
}

0 comments on commit 4b94f4b

Please sign in to comment.