Skip to content

tetragon: Get proper exex cwd in case of no arguments #683

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

Merged
merged 4 commits into from
Feb 17, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions pkg/observer/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@ func InitDataCache(size int) error {
return err
}

func DataAdd(id dataapi.DataEventId, msgData []byte) error {
size := len(msgData)
data, ok := dataMap.Get(id)
if !ok {
dataMap.Add(id, msgData)
} else {
data = append(data, msgData...)
dataMap.Add(id, data)
}

logger.GetLogger().WithFields(nil).Tracef("Data message received id %v, size %v, total %v", id, size, len(data))
return nil
}

func add(r *bytes.Reader, m *dataapi.MsgData) error {
size := m.Common.Size - uint32(unsafe.Sizeof(*m))
msgData := make([]byte, size)
Expand All @@ -37,16 +51,7 @@ func add(r *bytes.Reader, m *dataapi.MsgData) error {
return err
}

data, ok := dataMap.Get(m.Id)
if !ok {
dataMap.Add(m.Id, msgData)
} else {
data = append(data, msgData...)
dataMap.Add(m.Id, data)
}

logger.GetLogger().WithFields(nil).Tracef("Data message received id %v, size %v, total %v", m.Id, size, len(data))
return nil
return DataAdd(m.Id, msgData)
}

func DataGet(id dataapi.DataEventId) ([]byte, error) {
Expand Down Expand Up @@ -75,3 +80,7 @@ func HandleData(r *bytes.Reader) ([]Event, error) {
// we don't send the event further
return nil, nil
}

func DataPurge() {
dataMap.Purge()
}
4 changes: 4 additions & 0 deletions pkg/sensors/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ func execParse(reader *bytes.Reader) (processapi.MsgProcess, bool, error) {

cwd := args[unsafe.Sizeof(desc):]
cmdArgs = append(cmdArgs, cwd)
} else {
// no arguments, args should have just cwd
// reading it with split to get [][]byte type
cmdArgs = bytes.Split(args, []byte{0x00})
}

proc.Args = string(bytes.Join(cmdArgs[0:], []byte{0x00}))
Expand Down
191 changes: 187 additions & 4 deletions pkg/sensors/exec/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
package exec

import (
"bytes"
"context"
"encoding/binary"
"fmt"
"os"
"os/exec"
Expand All @@ -14,7 +16,9 @@ import (

"github.com/cilium/ebpf"
ec "github.com/cilium/tetragon/api/v1/tetragon/codegen/eventchecker"
api "github.com/cilium/tetragon/pkg/api/processapi"
"github.com/cilium/tetragon/pkg/api"
"github.com/cilium/tetragon/pkg/api/dataapi"
"github.com/cilium/tetragon/pkg/api/processapi"
"github.com/cilium/tetragon/pkg/bpf"
grpcexec "github.com/cilium/tetragon/pkg/grpc/exec"
"github.com/cilium/tetragon/pkg/jsonchecker"
Expand All @@ -23,6 +27,7 @@ import (
sm "github.com/cilium/tetragon/pkg/matchers/stringmatcher"
"github.com/cilium/tetragon/pkg/observer"
"github.com/cilium/tetragon/pkg/option"
proc "github.com/cilium/tetragon/pkg/process"
"github.com/cilium/tetragon/pkg/reader/namespace"
"github.com/cilium/tetragon/pkg/sensors"
"github.com/cilium/tetragon/pkg/sensors/base"
Expand All @@ -41,7 +46,7 @@ func TestMain(m *testing.M) {
}

func Test_msgToExecveKubeUnix(t *testing.T) {
event := api.MsgExecveEvent{}
event := processapi.MsgExecveEvent{}
idLength := procevents.BpfContainerIdLength

// Minikube has "docker-" prefix.
Expand Down Expand Up @@ -97,7 +102,7 @@ func Test_msgToExecveKubeUnix(t *testing.T) {
assert.Equal(t, idLength, len(kube.Docker))

// Empty event so we don't fail tests
for i := 0; i < api.DOCKER_ID_LENGTH; i++ {
for i := 0; i < processapi.DOCKER_ID_LENGTH; i++ {
event.Kube.Docker[i] = 0
}
// Not valid
Expand All @@ -107,7 +112,7 @@ func Test_msgToExecveKubeUnix(t *testing.T) {
assert.Empty(t, kube.Docker)

// Empty event so we don't fail tests
for i := 0; i < api.DOCKER_ID_LENGTH; i++ {
for i := 0; i < processapi.DOCKER_ID_LENGTH; i++ {
event.Kube.Docker[i] = 0
}
id = ":ba4c34f800cf9f92881fd55cea8e60d"
Expand Down Expand Up @@ -547,3 +552,181 @@ func TestExecPerfring(t *testing.T) {
}
t.Fatalf("failed to find exec event")
}

func TestExecParse(t *testing.T) {
if err := observer.InitDataCache(1024); err != nil {
t.Fatalf("observer.InitDataCache: %s", err)
}

exec := processapi.MsgExec{
Size: processapi.MSG_SIZEOF_EXECVE,
}

filename := []byte("/bin/krava")
cwd := []byte("/home/krava")

// Following tests prepare reader with MsgExec event plus additional data
// that follows it - filename, arguments, cwd
//
// The filename could be in form of data event or string. The arguments
// data is optional and can be only in form of data event. This setup is
// reflected in MsgExec::Flags.
//
// Based on the MsgExec::Flags the execParse function parses out MsgProcess
// object, and we retrieve and check its Args value with ArgsDecoder
// function which is used in GetProcess.

var err error

{
// - filename (string)
// - no args
// - cwd (string)

exec.Flags = 0
exec.Size = uint32(processapi.MSG_SIZEOF_EXECVE + len(filename) + len(cwd) + 1)

var buf bytes.Buffer
binary.Write(&buf, binary.LittleEndian, exec)
binary.Write(&buf, binary.LittleEndian, filename)
binary.Write(&buf, binary.LittleEndian, []byte{0})
binary.Write(&buf, binary.LittleEndian, cwd)

reader := bytes.NewReader(buf.Bytes())

process, empty, err := execParse(reader)
assert.NoError(t, err)

assert.Equal(t, string(filename), process.Filename)
assert.Equal(t, string(cwd), process.Args)
assert.Equal(t, empty, false)

decArgs, decCwd := proc.ArgsDecoder(process.Args, process.Flags)
assert.Equal(t, "", decArgs)
assert.Equal(t, string(cwd), decCwd)
}

observer.DataPurge()

{
// - filename (data event)
// - no args
// - cwd (string)

id := dataapi.DataEventId{Pid: 1, Time: 1}
desc := dataapi.DataEventDesc{Error: 0, Leftover: 0, Id: id}
err = observer.DataAdd(id, filename)
assert.NoError(t, err)

exec.Flags = api.EventDataFilename
exec.Size = uint32(processapi.MSG_SIZEOF_EXECVE + binary.Size(desc) + len(cwd))

var buf bytes.Buffer
binary.Write(&buf, binary.LittleEndian, exec)
binary.Write(&buf, binary.LittleEndian, desc)
binary.Write(&buf, binary.LittleEndian, cwd)

reader := bytes.NewReader(buf.Bytes())

process, empty, err := execParse(reader)
assert.NoError(t, err)

// execParse check
assert.Equal(t, string(filename), process.Filename)
assert.Equal(t, string(cwd), process.Args)
assert.Equal(t, empty, false)

// ArgsDecoder check
decArgs, decCwd := proc.ArgsDecoder(process.Args, process.Flags)
assert.Equal(t, "", decArgs)
assert.Equal(t, string(cwd), decCwd)
}

observer.DataPurge()

{
// - filename (string)
// - args (data event)
// - cwd (string)

var args []byte
args = append(args, 'a', 'r', 'g', '1', 0, 'a', 'r', 'g', '2', 0)

id := dataapi.DataEventId{Pid: 1, Time: 2}
desc := dataapi.DataEventDesc{Error: 0, Leftover: 0, Id: id}
err = observer.DataAdd(id, args)
assert.NoError(t, err)

exec.Flags = api.EventDataArgs
exec.Size = uint32(processapi.MSG_SIZEOF_EXECVE + len(filename) + binary.Size(desc) + len(cwd) + 1)

var buf bytes.Buffer
binary.Write(&buf, binary.LittleEndian, exec)
binary.Write(&buf, binary.LittleEndian, filename)
binary.Write(&buf, binary.LittleEndian, []byte{0})
binary.Write(&buf, binary.LittleEndian, desc)
binary.Write(&buf, binary.LittleEndian, cwd)

reader := bytes.NewReader(buf.Bytes())

process, empty, err := execParse(reader)
assert.NoError(t, err)

// execParse check
assert.Equal(t, string(filename), process.Filename)
assert.Equal(t, string(args)+string(cwd), process.Args)
assert.Equal(t, empty, false)

// ArgsDecoder check
decArgs, decCwd := proc.ArgsDecoder(process.Args, process.Flags)
assert.Equal(t, "arg1 arg2", decArgs)
assert.Equal(t, string(cwd), decCwd)
}

observer.DataPurge()

{
// - filename (data event)
// - args (data event)
// - cwd (string)

id1 := dataapi.DataEventId{Pid: 1, Time: 1}
desc1 := dataapi.DataEventDesc{Error: 0, Leftover: 0, Id: id1}
err = observer.DataAdd(id1, filename)
assert.NoError(t, err)

var args []byte
args = append(args, 'a', 'r', 'g', '1', 0, 'a', 'r', 'g', '2', 0)

id2 := dataapi.DataEventId{Pid: 1, Time: 2}
desc2 := dataapi.DataEventDesc{Error: 0, Leftover: 0, Id: id2}
err = observer.DataAdd(id2, args)
assert.NoError(t, err)

exec.Flags = api.EventDataFilename | api.EventDataArgs
exec.Size = uint32(processapi.MSG_SIZEOF_EXECVE + binary.Size(desc1) + binary.Size(desc2) + len(cwd))

var buf bytes.Buffer
binary.Write(&buf, binary.LittleEndian, exec)
binary.Write(&buf, binary.LittleEndian, desc1)
binary.Write(&buf, binary.LittleEndian, desc2)
binary.Write(&buf, binary.LittleEndian, cwd)

reader := bytes.NewReader(buf.Bytes())

process, empty, err := execParse(reader)
assert.NoError(t, err)

// execParse check
assert.Equal(t, string(filename), process.Filename)
assert.Equal(t, string(args)+string(cwd), process.Args)
assert.Equal(t, empty, false)

// ArgsDecoder check
decArgs, decCwd := proc.ArgsDecoder(process.Args, process.Flags)
assert.Equal(t, "arg1 arg2", decArgs)
assert.Equal(t, string(cwd), decCwd)
}

observer.DataPurge()
}