Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
geyslan committed Jul 8, 2023
1 parent 068f5ee commit 34f4c5e
Show file tree
Hide file tree
Showing 28 changed files with 683 additions and 173 deletions.
166 changes: 82 additions & 84 deletions cmd/tracee-rules/input_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package main

import (
"encoding/gob"
"encoding/json"
"errors"
"io"
"os"
"testing"

Expand Down Expand Up @@ -165,85 +163,85 @@ func TestSetupTraceeJSONInputSource(t *testing.T) {
}
}

func TestSetupTraceeGobInputSource(t *testing.T) {
testCases := []struct {
testName string
events []trace.Event
expectedError error
}{
{
testName: "one event",
events: []trace.Event{
{
EventName: "Yankees are the best team in baseball",
},
},
expectedError: nil,
},
{
testName: "two events",
events: []trace.Event{
{
EventName: "Yankees are the best team in baseball",
},
{
EventName: "I hate the Red Sox so much",
},
},
expectedError: nil,
},
{
testName: "three events",
events: []trace.Event{
{
EventName: "Yankees are the best team in baseball",
},
{
EventName: "I hate the Red Sox so much",
},
{
EventName: "Aaron Judge is my idol",
},
},
expectedError: nil,
},
}

for _, testCase := range testCases {
t.Run(testCase.testName, func(t *testing.T) {
// Setup temp file that tracee-rules reads from
f, err := os.CreateTemp("", "TestSetupTraceeGobInputSource-")
if err != nil {
t.Error(err)
}
defer func() {
_ = f.Close()
_ = os.RemoveAll(f.Name())
}()

encoder := gob.NewEncoder(f)
for _, ev := range testCase.events {
err = encoder.Encode(ev)
if err != nil {
t.Error(err)
}
}
f.Seek(0, io.SeekStart)

// Set up reading from the file
opts := &traceeInputOptions{inputFile: f, inputFormat: gobInputFormat}
eventsChan, err := setupTraceeGobInputSource(opts)
assert.Equal(t, testCase.expectedError, err)

readEvents := []trace.Event{}

for e := range eventsChan {
traceeEvt, ok := e.Payload.(trace.Event)
require.True(t, ok)
readEvents = append(readEvents, traceeEvt)
}

assert.Equal(t, testCase.events, readEvents)
})
}
}
// func TestSetupTraceeGobInputSource(t *testing.T) {
// testCases := []struct {
// testName string
// events []trace.Event
// expectedError error
// }{
// {
// testName: "one event",
// events: []trace.Event{
// {
// EventName: "Yankees are the best team in baseball",
// },
// },
// expectedError: nil,
// },
// {
// testName: "two events",
// events: []trace.Event{
// {
// EventName: "Yankees are the best team in baseball",
// },
// {
// EventName: "I hate the Red Sox so much",
// },
// },
// expectedError: nil,
// },
// {
// testName: "three events",
// events: []trace.Event{
// {
// EventName: "Yankees are the best team in baseball",
// },
// {
// EventName: "I hate the Red Sox so much",
// },
// {
// EventName: "Aaron Judge is my idol",
// },
// },
// expectedError: nil,
// },
// }

// for _, testCase := range testCases {
// t.Run(testCase.testName, func(t *testing.T) {
// // Setup temp file that tracee-rules reads from
// f, err := os.CreateTemp("", "TestSetupTraceeGobInputSource-")
// if err != nil {
// t.Error(err)
// }
// defer func() {
// _ = f.Close()
// _ = os.RemoveAll(f.Name())
// }()

// encoder := gob.NewEncoder(f)
// for _, ev := range testCase.events {
// err = encoder.Encode(ev)
// if err != nil {
// t.Error(err)
// }
// }
// f.Seek(0, io.SeekStart)

// // Set up reading from the file
// opts := &traceeInputOptions{inputFile: f, inputFormat: gobInputFormat}
// eventsChan, err := setupTraceeGobInputSource(opts)
// assert.Equal(t, testCase.expectedError, err)

// readEvents := []trace.Event{}

// for e := range eventsChan {
// traceeEvt, ok := e.Payload.(trace.Event)
// require.True(t, ok)
// readEvents = append(readEvents, traceeEvt)
// }

// assert.Equal(t, testCase.events, readEvents)
// })
// }
// }
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,5 @@ require (
)

replace github.com/kubernetes/cri-api => k8s.io/cri-api v0.23.5-rc.0

replace github.com/aquasecurity/tracee/types => ./types
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ github.com/aquasecurity/libbpfgo v0.4.8-libbpf-1.2.0.0.20230509162948-80f41e18e6
github.com/aquasecurity/libbpfgo v0.4.8-libbpf-1.2.0.0.20230509162948-80f41e18e690/go.mod h1:UD3Mfr+JZ/ASK2VMucI/zAdEhb35LtvYXvAUdrdqE9s=
github.com/aquasecurity/libbpfgo/helpers v0.4.6-0.20230321190037-f591a2c5734f h1:l127H3NqJBmw+XMt+haBOeZIrBppuw7TJz26cWMI9kY=
github.com/aquasecurity/libbpfgo/helpers v0.4.6-0.20230321190037-f591a2c5734f/go.mod h1:j/TQLmsZpOIdF3CnJODzYngG4yu1YoDCoRMELxkQSSA=
github.com/aquasecurity/tracee/types v0.0.0-20230602152109-e48d0a548fbf h1:bSWqjqjFPGyn+thqof/rph4A5jSqd2d7xWJK5MGMb0I=
github.com/aquasecurity/tracee/types v0.0.0-20230602152109-e48d0a548fbf/go.mod h1:kHvgUMXGq5QEqSLPgu4RwGSJEoCuMQJnEkGk8OAcSUc=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
Expand Down
7 changes: 6 additions & 1 deletion pkg/cmd/cobra/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ func getConfigAndPrinterFromPoliciesFlags(cfg config.Config, policyFlags, output
return cfg, nil, err
}
cfg.Policies = policies
if _, err := cfg.Policies.StoreSnapshot(); err != nil {
return cfg, nil, err
}

outputFlags, err = getOutputFlagsFromPolicies(outputFlags, policyFiles)
if err != nil {
Expand Down Expand Up @@ -60,8 +63,10 @@ func getConfigAndPrinterFromFilterFlags(cfg config.Config, filterFlags, outputFl
if err != nil {
return cfg, nil, err
}

cfg.Policies = policies
if _, err := cfg.Policies.StoreSnapshot(); err != nil {
return cfg, nil, err
}

// Output command line flags
output, err := flags.PrepareOutput(outputFlags, true)
Expand Down
1 change: 1 addition & 0 deletions pkg/cmd/flags/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ func CreatePolicies(filterMap PolicyFilterMap, newBinary bool) (*policy.Policies
}

policies := policy.NewPolicies()
policies.SetVersion(1)
for policyIdx, policyFilters := range filterMap {
p := policy.NewPolicy()
p.ID = policyIdx
Expand Down
4 changes: 3 additions & 1 deletion pkg/cmd/urfave/urfave.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,10 @@ func GetTraceeRunner(c *cli.Context, version string) (cmd.Runner, error) {
if err != nil {
return runner, err
}

cfg.Policies = policies
if _, err := cfg.Policies.StoreSnapshot(); err != nil {
return runner, err
}

broadcast, err := printer.NewBroadcast(output.PrinterConfigs, cmd.GetContainerMode(cfg))
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions pkg/ebpf/c/maps.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ enum tail_call_id_e
BPF_HASH(kconfig_map, u32, u32, 10240); // kernel config variables
BPF_HASH(containers_map, u32, u8, 10240); // map cgroup id to container status {EXISTED, CREATED, STARTED}
BPF_HASH(args_map, u64, args_t, 1024); // persist args between function entry and return

// policies filters
BPF_HASH(uid_filter, u32, eq_t, 256); // filter events by UID, for specific UIDs either by == or !=
BPF_HASH(pid_filter, u32, eq_t, 256); // filter events by PID
BPF_HASH(mnt_ns_filter, u64, eq_t, 256); // filter events by mount namespace id
Expand All @@ -86,6 +88,7 @@ BPF_HASH(uts_ns_filter, string_filter_t, eq_t, 256); // filter eve
BPF_HASH(comm_filter, string_filter_t, eq_t, 256); // filter events by command name
BPF_HASH(cgroup_id_filter, u32, eq_t, 256); // filter events by cgroup id
BPF_HASH(binary_filter, binary_t, eq_t, 256); // filter events by binary path and mount namespace

BPF_HASH(events_map, u32, event_config_t, MAX_EVENT_ID); // map to persist event configuration data
BPF_HASH(sys_32_to_64_map, u32, u32, 1024); // map 32bit to 64bit syscalls
BPF_HASH(process_tree_map, u32, eq_t, 10240); // filter events by the ancestry of the traced process
Expand Down
2 changes: 1 addition & 1 deletion pkg/ebpf/c/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ typedef struct config_entry {
u32 tracee_pid;
u32 options;
u32 cgroup_v1_hid;
u32 padding; // free for further use
u32 filter_version;
// enabled scopes bitmask per filter
u64 uid_filter_enabled_scopes;
u64 pid_filter_enabled_scopes;
Expand Down
50 changes: 46 additions & 4 deletions pkg/ebpf/events_pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/aquasecurity/tracee/pkg/errfmt"
"github.com/aquasecurity/tracee/pkg/events"
"github.com/aquasecurity/tracee/pkg/logger"
"github.com/aquasecurity/tracee/pkg/policy"
"github.com/aquasecurity/tracee/pkg/utils"
"github.com/aquasecurity/tracee/types/trace"
)
Expand Down Expand Up @@ -182,6 +183,9 @@ func (t *Tracee) decodeEvents(outerCtx context.Context, sourceChan chan []byte)
stackAddresses, _ = t.getStackAddresses(ctx.StackID)
}

// Save the original bpf_ktime_get_ns() timestamp
origEventTS := ctx.Ts

// Currently, the timestamp received from the bpf code is of the monotonic clock.
// Todo: The monotonic clock doesn't take into account system sleep time.
// Starting from kernel 5.7, we can get the timestamp relative to the system boot time instead which is preferable.
Expand Down Expand Up @@ -248,6 +252,17 @@ func (t *Tracee) decodeEvents(outerCtx context.Context, sourceChan chan []byte)
Syscall: syscall,
}

policies, err := policy.GetSnapshot(int64(origEventTS))
if err != nil {
t.handleError(err)
_ = t.stats.EventsFiltered.Increment()
continue
}
// fmt.Printf("START OF PIPELINE %p\n", policies)
// fmt.Printf("event Timestamp: %d\n", origEventTS)

evt.Policies = unsafe.Pointer(policies)

// If there aren't any policies that need filtering in userland, tracee **may** skip
// this event, as long as there aren't any derivatives or signatures that depend on it.
// Some base events (derivative and signatures) might not have set related policy bit,
Expand Down Expand Up @@ -281,13 +296,18 @@ func (t *Tracee) matchPolicies(event *trace.Event) uint64 {
eventID := events.ID(event.EventID)
bitmap := event.MatchedPoliciesKernel

// fmt.Printf("event: %+v\n", event)
// fmt.Printf("event.Policies %x\n", event.Policies)
policies := (*policy.Policies)(event.Policies)
// fmt.Printf("policies %p\n", policies)

// Short circuit if there are no policies in userland that need filtering.
if bitmap&t.config.Policies.FilterableInUserland() == 0 {
if bitmap&policies.FilterableInUserland() == 0 {
event.MatchedPoliciesUser = bitmap // store untoched bitmap to be used in sink stage
return bitmap
}

for p := range t.config.Policies.FilterableInUserlandMap() { // range through each userland filterable policy
for p := range policies.FilterableInUserlandMap() { // range through each userland filterable policy
// Policy ID is the bit offset in the bitmap.
bitOffset := uint(p.ID)

Expand Down Expand Up @@ -437,8 +457,20 @@ func (t *Tracee) processEvents(ctx context.Context, in <-chan *trace.Event) (
continue
}

var policies *policy.Policies
if event.Policies != nil {
policies = (*policy.Policies)(event.Policies)
} else {
pols, err := policy.GetLastSnapshot()
if err != nil {
t.handleError(err)
continue
}
policies = pols
}

// Get a bitmap with all policies containing container filters
policiesWithContainerFilter := t.config.Policies.ContainerFilterEnabled()
policiesWithContainerFilter := policies.ContainerFilterEnabled()

// Filter out events that don't have a container ID from all the policies that have
// container filters. This will guarantee that any of those policies won't get matched
Expand Down Expand Up @@ -514,6 +546,15 @@ func (t *Tracee) deriveEvents(ctx context.Context, in <-chan *trace.Event) (
}

for i := range derivatives {
if event.Policies == nil {
pols, err := policy.GetLastSnapshot()
if err != nil {
t.handleError(err)
continue
}
derivatives[i].Policies = unsafe.Pointer(pols)
}

// Skip events that dont work with filtering due to missing types being handled.
// https://github.com/aquasecurity/tracee/issues/2486
switch events.ID(derivatives[i].EventID) {
Expand Down Expand Up @@ -560,8 +601,9 @@ func (t *Tracee) sinkEvents(ctx context.Context, in <-chan *trace.Event) <-chan
continue
}

policies := (*policy.Policies)(event.Policies)
// Populate the event with the names of the matched policies.
event.MatchedPolicies = t.config.Policies.MatchedNames(event.MatchedPoliciesUser)
event.MatchedPolicies = policies.MatchedNames(event.MatchedPoliciesUser)

// Parse args here if the rule engine is not enabled (parsed there if it is).
if !t.config.EngineConfig.Enabled {
Expand Down
Loading

0 comments on commit 34f4c5e

Please sign in to comment.