From 9bae12eea3316f20363396147915f4be2fb2b170 Mon Sep 17 00:00:00 2001 From: Rafael David Tinoco Date: Sat, 29 Jul 2023 02:29:12 -0300 Subject: [PATCH] chore(cmd): improve list of events output using definitions - tabled event list output - include --wide option for better readability - use recent factored event definitions and event groups concept --- cmd/tracee-ebpf/main.go | 2 +- cmd/tracee/cmd/list.go | 17 +++-- go.mod | 3 + go.sum | 8 +++ pkg/cmd/flags/filter.go | 4 +- pkg/cmd/list.go | 92 +++++++++++++++++++++++++++ pkg/cmd/tracee.go | 81 ----------------------- pkg/cmd/tracee_test.go | 37 ----------- pkg/ebpf/tracee.go | 3 +- pkg/events/definition.go | 8 +++ pkg/events/definition_dependencies.go | 1 + pkg/events/definition_group.go | 19 ++++-- 12 files changed, 143 insertions(+), 132 deletions(-) create mode 100644 pkg/cmd/list.go delete mode 100644 pkg/cmd/tracee_test.go diff --git a/cmd/tracee-ebpf/main.go b/cmd/tracee-ebpf/main.go index 7320f08addf4..7b65f0548034 100644 --- a/cmd/tracee-ebpf/main.go +++ b/cmd/tracee-ebpf/main.go @@ -34,7 +34,7 @@ func main() { flags.PrintAndExitIfHelp(c) if c.Bool("list") { - cmd.PrintEventList(false) // list events + cmd.PrintEventList(false, false) // list events return nil } initialize.SetLibbpfgoCallbacks() diff --git a/cmd/tracee/cmd/list.go b/cmd/tracee/cmd/list.go index 48130f4132cc..27f44bff2ead 100644 --- a/cmd/tracee/cmd/list.go +++ b/cmd/tracee/cmd/list.go @@ -6,7 +6,7 @@ import ( "github.com/open-policy-agent/opa/compile" "github.com/spf13/cobra" - tcmd "github.com/aquasecurity/tracee/pkg/cmd" + "github.com/aquasecurity/tracee/pkg/cmd" "github.com/aquasecurity/tracee/pkg/cmd/initialize" "github.com/aquasecurity/tracee/pkg/events" "github.com/aquasecurity/tracee/pkg/logger" @@ -15,6 +15,12 @@ import ( func init() { rootCmd.AddCommand(listCmd) + listCmd.Flags().BoolP( + "wide", + "w", + false, + "no wrapping of output lines", + ) listCmd.Flags().StringArray( "signatures-dir", []string{}, @@ -27,9 +33,9 @@ var listCmd = &cobra.Command{ Aliases: []string{"l"}, Short: "List traceable events", Long: ``, - Run: func(cmd *cobra.Command, args []string) { + Run: func(c *cobra.Command, args []string) { // Get signatures to update event list - sigsDir, err := cmd.Flags().GetStringArray("signatures-dir") + sigsDir, err := c.Flags().GetStringArray("signatures-dir") if err != nil { logger.Fatalw("Failed to get signatures-dir flag", "err", err) os.Exit(1) @@ -48,7 +54,10 @@ var listCmd = &cobra.Command{ } initialize.CreateEventsFromSignatures(events.StartSignatureID, sigs) - tcmd.PrintEventList(true) // list events + + includeSigs := true + wideOutput := c.Flags().Lookup("wide").Value.String() == "true" + cmd.PrintEventList(includeSigs, wideOutput) // list events }, DisableFlagsInUseLine: true, } diff --git a/go.mod b/go.mod index 8b1e0454bec9..7d5646c510bd 100644 --- a/go.mod +++ b/go.mod @@ -60,6 +60,7 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-runewidth v0.0.10 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect @@ -68,6 +69,7 @@ require ( github.com/pelletier/go-toml/v2 v2.0.7 // indirect github.com/philhofer/fwd v1.1.2 // indirect github.com/pyroscope-io/dotnetdiag v1.2.1 // indirect + github.com/rivo/uniseg v0.2.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -136,6 +138,7 @@ require ( github.com/moby/sys/signal v0.7.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/olekukonko/tablewriter v0.0.5 github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc3 // indirect github.com/opencontainers/runc v1.1.7 // indirect diff --git a/go.sum b/go.sum index 1d91d6f5b3c6..ab713b927b31 100644 --- a/go.sum +++ b/go.sum @@ -298,6 +298,9 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg= +github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= @@ -331,6 +334,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= github.com/open-policy-agent/opa v0.52.0 h1:Rv3F+VCDqsufaiYy/3S9/Iuk0yfcREK4iZmWbNsKZjA= @@ -370,6 +375,9 @@ github.com/pyroscope-io/pyroscope v0.37.2 h1:MOgLU/oO7VfV6jWqb0xoFH/YPSVbWD5pGsX github.com/pyroscope-io/pyroscope v0.37.2/go.mod h1:r4wq4ajJvN7g1OeXGyNvmwzBfQ+Tm5alYvmxqEQSTsc= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= diff --git a/pkg/cmd/flags/filter.go b/pkg/cmd/flags/filter.go index 12c6ea752241..3d191406f1c9 100644 --- a/pkg/cmd/flags/filter.go +++ b/pkg/cmd/flags/filter.go @@ -107,9 +107,9 @@ func prepareEventsToTrace(eventFilter eventFilter, eventsNameToID map[string]eve isExcluded := make(map[events.ID]bool) // build a map: k:set, v:eventID - for id, eventDefinition := range events.Core.GetDefinitions() { + for _, eventDefinition := range events.Core.GetDefinitions() { for _, set := range eventDefinition.GetSets() { - setsToEvents[set] = append(setsToEvents[set], id) + setsToEvents[set] = append(setsToEvents[set], eventDefinition.GetID()) } } diff --git a/pkg/cmd/list.go b/pkg/cmd/list.go new file mode 100644 index 000000000000..f72d65555056 --- /dev/null +++ b/pkg/cmd/list.go @@ -0,0 +1,92 @@ +package cmd + +import ( + "fmt" + "os" + "strings" + + "github.com/olekukonko/tablewriter" + + "github.com/aquasecurity/tracee/pkg/events" + "github.com/aquasecurity/tracee/types/trace" +) + +func PrintEventList(includeSigs bool, wideOutput bool) { + // TODO: Create String() method in types trace.ArgMeta + paramsToString := func(params []trace.ArgMeta) string { + strSlice := []string{} + for _, p := range params { + strSlice = append(strSlice, p.Type+" "+p.Name) + } + return strings.Join(strSlice, ", ") + } + + allDefinitions := events.Core.GetDefinitions() + + // Use tablewriter to print events in a table + newTable := func() *tablewriter.Table { + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"Rule", "Sets", "Arguments"}) + table.SetColMinWidth(0, 15) + table.SetColMinWidth(1, 15) + table.SetColMinWidth(2, 40) + table.SetAutoWrapText(!wideOutput) + table.SetRowLine(!wideOutput) + table.SetAutoFormatHeaders(true) + table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) + table.SetAlignment(tablewriter.ALIGN_LEFT) + table.SetHeaderLine(true) + table.SetBorder(true) + return table + } + + tableRender := func(table *tablewriter.Table, title string) *tablewriter.Table { + fmt.Printf("\n" + title + "\n\n") + table.Render() + return newTable() + } + + getRow := func(evtDef events.Definition) []string { + return []string{ + evtDef.GetName(), + strings.Join(evtDef.GetSets(), ", "), + paramsToString(evtDef.GetParams()), + } + } + + fmt.Printf("Tracee supports the following events (use --wide for wider output):\n") + table := newTable() + + // Signature Events + for _, evtDef := range allDefinitions { + if evtDef.IsSignature() { + table.AppendBulk([][]string{getRow(evtDef)}) + } + } + table = tableRender(table, "Signature Events") + + // Syscall Events + for _, evtDef := range allDefinitions { + if evtDef.IsSyscall() { + table.AppendBulk([][]string{getRow(evtDef)}) + } + } + table = tableRender(table, "Syscall Events") + + // Other Events + for _, evtDef := range allDefinitions { + if !evtDef.IsInternal() && !evtDef.IsSyscall() && + !evtDef.IsSignature() && !evtDef.IsNetwork() { + table.AppendBulk([][]string{getRow(evtDef)}) + } + } + table = tableRender(table, "Other Events") + + // Network Events + for _, evtDef := range allDefinitions { + if evtDef.IsNetwork() { + table.AppendBulk([][]string{getRow(evtDef)}) + } + } + tableRender(table, "Network Events") +} diff --git a/pkg/cmd/tracee.go b/pkg/cmd/tracee.go index b759fc70de1f..04bbd73fec7f 100644 --- a/pkg/cmd/tracee.go +++ b/pkg/cmd/tracee.go @@ -2,17 +2,14 @@ package cmd import ( "context" - "fmt" "os" "strconv" - "strings" "syscall" "github.com/aquasecurity/tracee/pkg/cmd/printer" "github.com/aquasecurity/tracee/pkg/config" tracee "github.com/aquasecurity/tracee/pkg/ebpf" "github.com/aquasecurity/tracee/pkg/errfmt" - "github.com/aquasecurity/tracee/pkg/events" "github.com/aquasecurity/tracee/pkg/logger" "github.com/aquasecurity/tracee/pkg/server" "github.com/aquasecurity/tracee/pkg/utils" @@ -104,84 +101,6 @@ func (r Runner) Run(ctx context.Context) error { } } -func PrintEventList(printRulesSet bool) { - padChar := " " - titleHeaderPadFirst := getPad(padChar, 24) - titleHeaderPadSecond := getPad(padChar, 36) - - var b strings.Builder - - if printRulesSet { - b.WriteString("Rules: " + titleHeaderPadFirst + "Sets:" + titleHeaderPadSecond + "Arguments:\n") - b.WriteString("_____ " + titleHeaderPadFirst + "____ " + titleHeaderPadSecond + "_________" + "\n\n") - printEventGroup(&b, events.StartSignatureID, events.MaxSignatureID) - b.WriteString("\n") - } - - titleHeaderPadFirst = getPad(padChar, 17) - b.WriteString("System Calls: " + titleHeaderPadFirst + "Sets:" + titleHeaderPadSecond + "Arguments:\n") - b.WriteString("____________ " + titleHeaderPadFirst + "____ " + titleHeaderPadSecond + "_________" + "\n\n") - printEventGroup(&b, 0, events.MaxSyscallID) - b.WriteString("\n\nOther Events: " + titleHeaderPadFirst + "Sets:" + titleHeaderPadSecond + "Arguments:\n") - b.WriteString("____________ " + titleHeaderPadFirst + "____ " + titleHeaderPadSecond + "_________\n\n") - printEventGroup(&b, events.SysEnter, events.MaxCommonID) - printEventGroup(&b, events.InitNamespaces, events.MaxUserSpace) - - titleHeaderPadFirst = getPad(padChar, 15) - b.WriteString("\n\nNetwork Events: " + titleHeaderPadFirst + "Sets:" + titleHeaderPadSecond + "Arguments:\n") - b.WriteString("______________ " + titleHeaderPadFirst + "____ " + titleHeaderPadSecond + "_________\n\n") - printEventGroup(&b, events.NetPacketIPv4, events.MaxUserNetID) - fmt.Println(b.String()) -} - -func printEventGroup(b *strings.Builder, firstEventID, lastEventID events.ID) { - for i := firstEventID; i < lastEventID; i++ { - if !events.Core.IsDefined(i) { - continue - } - eventDefinition := events.Core.GetDefinitionByID(i) - if eventDefinition.IsInternal() { - continue - } - if eventDefinition.GetSets() != nil { - eventSets := fmt.Sprintf( - "%-30s %-40s %s\n", - eventDefinition.GetName(), - fmt.Sprintf("%v", eventDefinition.GetSets()), getFormattedEventParams(i), - ) - b.WriteString(eventSets) - } else { - b.WriteString(eventDefinition.GetName() + "\n") - } - } -} - -func getFormattedEventParams(eventID events.ID) string { - if !events.Core.IsDefined(eventID) { - return "()" - } - var verboseEventParams string - verboseEventParams += "(" - prefix := "" - for index, arg := range events.Core.GetDefinitionByID(eventID).GetParams() { - if index == 0 { - verboseEventParams += arg.Type + " " + arg.Name - prefix = ", " - continue - } - verboseEventParams += prefix + arg.Type + " " + arg.Name - } - verboseEventParams += ")" - return verboseEventParams -} - -func getPad(padChar string, padLength int) (pad string) { - for i := 0; i < padLength; i++ { - pad += padChar - } - return pad -} - func GetContainerMode(cfg config.Config) config.ContainerMode { containerMode := config.ContainerModeDisabled diff --git a/pkg/cmd/tracee_test.go b/pkg/cmd/tracee_test.go deleted file mode 100644 index 90d4f9d2a2df..000000000000 --- a/pkg/cmd/tracee_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package cmd - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/aquasecurity/tracee/pkg/events" -) - -func Test_getFormattedEventParams(t *testing.T) { - testCases := []struct { - input events.ID - output string - }{ - { - input: events.Write, - output: "(int fd, void* buf, size_t count)", - }, - { - input: events.RtSigreturn, - output: "()", - }, - { - input: events.RtSigtimedwait, - output: "(const sigset_t* set, siginfo_t* info, const struct timespec* timeout, size_t sigsetsize)", - }, - { - input: 99999999, // unknown event - output: "()", - }, - } - - for _, tc := range testCases { - assert.Equal(t, tc.output, getFormattedEventParams(tc.input)) - } -} diff --git a/pkg/ebpf/tracee.go b/pkg/ebpf/tracee.go index 244eb616ecf6..690e4cbbff67 100644 --- a/pkg/ebpf/tracee.go +++ b/pkg/ebpf/tracee.go @@ -929,7 +929,8 @@ func (t *Tracee) validateKallsymsDependencies() { func (t *Tracee) populateBPFMaps() error { // Initialize events parameter types map eventsParams := make(map[events.ID][]bufferdecoder.ArgType) - for id, eventDefinition := range events.Core.GetDefinitions() { + for _, eventDefinition := range events.Core.GetDefinitions() { + id := eventDefinition.GetID() params := eventDefinition.GetParams() for _, param := range params { eventsParams[id] = append(eventsParams[id], bufferdecoder.GetParamType(param.Type)) diff --git a/pkg/events/definition.go b/pkg/events/definition.go index 60e3210695ff..3abfc97de3b6 100644 --- a/pkg/events/definition.go +++ b/pkg/events/definition.go @@ -85,3 +85,11 @@ func (d Definition) IsSignature() bool { return false } + +func (d Definition) IsNetwork() bool { + if d.id >= NetPacketIPv4 && d.id <= MaxUserNetID { + return true + } + + return false +} diff --git a/pkg/events/definition_dependencies.go b/pkg/events/definition_dependencies.go index 51c5017b4a10..faf3b938fa57 100644 --- a/pkg/events/definition_dependencies.go +++ b/pkg/events/definition_dependencies.go @@ -6,6 +6,7 @@ import ( "github.com/aquasecurity/tracee/pkg/ebpf/probes" ) +// Dependencies is a struct that holds all the dependencies of a given event definition. type Dependencies struct { ids []ID kSymbols []KSymbol diff --git a/pkg/events/definition_group.go b/pkg/events/definition_group.go index 10760826ff45..5a58715059bc 100644 --- a/pkg/events/definition_group.go +++ b/pkg/events/definition_group.go @@ -1,6 +1,7 @@ package events import ( + "sort" "sync" "github.com/aquasecurity/tracee/pkg/errfmt" @@ -16,6 +17,12 @@ type EventState struct { // ATTENTION: the definition group is instantiable (all the rest is immutable) +type ByID []Definition + +func (a ByID) Len() int { return len(a) } +func (a ByID) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a ByID) Less(i, j int) bool { return a[i].id < a[j].id } + // // DefinitionGroup // @@ -36,17 +43,17 @@ func NewDefinitionGroup() *DefinitionGroup { // GetDefinitions returns a new map of existing definitions. // TODO: iterate internally after event definition refactor is finished ? -func (e *DefinitionGroup) GetDefinitions() map[ID]Definition { +func (e *DefinitionGroup) GetDefinitions() []Definition { e.mutex.RLock() defer e.mutex.RUnlock() - mapCopy := make(map[ID]Definition, len(e.definitions)) - - for id, def := range e.definitions { - mapCopy[id] = def + definitions := make([]Definition, 0, len(e.definitions)) + for _, def := range e.definitions { + definitions = append(definitions, def) } + sort.Sort(ByID(definitions)) - return mapCopy + return definitions } // GetDefinitionIDByName returns a definition ID by its name.