Skip to content

Commit

Permalink
feat(analyze): add legacy output
Browse files Browse the repository at this point in the history
Add output format for flag marked as "legacy". The output will be the
same format as given for findings in the rawjson.tmpl template in
tracee-rules.
  • Loading branch information
NDStrahilevitz committed Nov 19, 2024
1 parent 21a68c7 commit 77b132d
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 20 deletions.
45 changes: 36 additions & 9 deletions cmd/tracee/cmd/analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/aquasecurity/tracee/pkg/analyze"
"github.com/aquasecurity/tracee/pkg/cmd/flags"
"github.com/aquasecurity/tracee/pkg/cmd/printer"
"github.com/aquasecurity/tracee/pkg/config"
"github.com/aquasecurity/tracee/pkg/logger"
)

Expand Down Expand Up @@ -63,7 +64,7 @@ func init() {
}

var analyzeCmd = &cobra.Command{
Use: "tracee analyze --input <json_file>",
Use: "tracee analyze --source <json_file>",
Aliases: []string{},
Short: "Analyze past events with signature events [Experimental]",
Long: `Analyze allow you to explore signature events with past events.
Expand All @@ -72,7 +73,7 @@ Tracee can be used to collect events and store it in a file. This file can be us
eg:
tracee --events ptrace --output=json:events.json
tracee analyze --events anti_debugging --input events.json`,
tracee analyze --events anti_debugging --source events.json`,
PreRun: func(cmd *cobra.Command, args []string) {
bindViperFlag(cmd, "events")
bindViperFlag(cmd, "source")
Expand Down Expand Up @@ -106,17 +107,41 @@ func command(cmd *cobra.Command, args []string) {

// Set up printer output (outpath:format)
outputArg := viper.GetString("output")

// placeholder printer for legacy mode
p, err := printer.New(config.PrinterConfig{
OutFile: os.Stdout,
Kind: "ignore",
})

if err != nil {
logger.Fatalw("Failed to initialize initial printer")
}

isLegacy := false
legacyOutFile := os.Stdout
outputParts := strings.SplitN(outputArg, ":", 2)
if len(outputParts) != 2 {
logger.Fatalw("Failed to prepare output format (must be of format <output_path>:<format>)")
}
printerCfg, err := flags.PreparePrinterConfig(outputParts[1], outputParts[0])
if err != nil {
logger.Fatalw("Failed to prepare output configuration", "error", err)
}
p, err := printer.New(printerCfg)
if err != nil {
logger.Fatalw("Failed to create printer", "error", err)

if outputParts[1] == "legacy" {
isLegacy = true
if outputParts[0] != "stdout" {
legacyOutFile, err = flags.CreateOutputFile(outputParts[0])
if err != nil {
logger.Fatalw("Failed to create output file for legacy output")
}
}
} else {
printerCfg, err := flags.PreparePrinterConfig(outputParts[1], outputParts[0])
if err != nil {
logger.Fatalw("Failed to prepare output configuration", "error", err)
}
p, err = printer.New(printerCfg)
if err != nil {
logger.Fatalw("Failed to create printer", "error", err)
}
}

// Rego command line flags
Expand All @@ -140,6 +165,8 @@ func command(cmd *cobra.Command, args []string) {
Rego: rego,
Source: sourceFile,
Printer: p,
Legacy: isLegacy,
LegacyOut: legacyOutFile,
SignatureDirs: signatureDirs,
SignatureEvents: signatureEvents,
})
Expand Down
54 changes: 47 additions & 7 deletions pkg/analyze/analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bufio"
"context"
"encoding/json"
"fmt"
"os"
"os/signal"
"syscall"
Expand All @@ -25,6 +26,8 @@ type Config struct {
Rego rego.Config
Source *os.File
Printer printer.EventPrinter
Legacy bool // TODO: remove once tracee-rules legacy is over
LegacyOut *os.File
SignatureDirs []string
SignatureEvents []string
}
Expand Down Expand Up @@ -87,6 +90,14 @@ func Analyze(cfg Config) {

go sigEngine.Start(signalCtx)

// decide process output
var process func(*detect.Finding)
if cfg.Legacy {
process = processLegacy(cfg.LegacyOut)
} else {
process = processWithPrinter(cfg.Printer)
}

// producer
go produce(fileReadCtx, stop, cfg.Source, engineInput)

Expand All @@ -99,7 +110,7 @@ func Analyze(cfg Config) {
if !ok {
return
}
process(finding, cfg.Printer)
process(finding)
case <-fileReadCtx.Done():
// ensure the engineInput channel will be closed
goto drain
Expand All @@ -118,7 +129,7 @@ drain:
return
}

process(finding, cfg.Printer)
process(finding)
default:
return
}
Expand Down Expand Up @@ -153,13 +164,42 @@ func produce(ctx context.Context, cancel context.CancelFunc, inputFile *os.File,
}
}

func process(finding *detect.Finding, printer printer.EventPrinter) {
event, err := findings.FindingToEvent(finding)
if err != nil {
logger.Fatalw("Failed to convert finding to event", "err", err)
func processWithPrinter(p printer.EventPrinter) func(finding *detect.Finding) {
return func(finding *detect.Finding) {
event, err := findings.FindingToEvent(finding)
if err != nil {
logger.Fatalw("Failed to convert finding to event", "err", err)
}

p.Print(*event)
}
}

func processLegacy(outF *os.File) func(finding *detect.Finding) {
return func(finding *detect.Finding) {
evt, ok := finding.Event.Payload.(trace.Event)
if !ok {
logger.Fatalw("Failed to extract finding event payload (legacy output)")
}
out := legacyOutput{
Data: finding.GetData(),
Event: evt,
SigMetadata: finding.SigMetadata,
}

outBytes, err := json.Marshal(out)
if err != nil {
logger.Fatalw("Failed to convert finding to legacy output", "err", err)
}

fmt.Fprintln(outF, string(outBytes))
}
}

printer.Print(*event)
type legacyOutput struct {
Data map[string]any
Event trace.Event
SigMetadata detect.SignatureMetadata
}

func getSigsNames(signatures []detect.Signature) []string {
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/flags/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func PrepareLogger(logOptions []string, newBinary bool) (logger.LoggingConfig, e
return logger.LoggingConfig{}, invalidLogOptionValue(nil, opt, newBinary)
}

w, err = createFile(vals[1])
w, err = CreateOutputFile(vals[1])
if err != nil {
return logger.LoggingConfig{}, err
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/cmd/flags/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func PreparePrinterConfig(printerKind string, outputPath string) (config.Printer
var err error

if outputPath != "stdout" && printerKind != "forward" && printerKind != "webhook" {
outFile, err = createFile(outputPath)
outFile, err = CreateOutputFile(outputPath)
if err != nil {
return config.PrinterConfig{}, err
}
Expand Down Expand Up @@ -239,7 +239,7 @@ func parseOption(outputParts []string, traceeConfig *config.OutputConfig, newBin
}

// creates *os.File for the given path
func createFile(path string) (*os.File, error) {
func CreateOutputFile(path string) (*os.File, error) {
fileInfo, err := os.Stat(path)
if err == nil && fileInfo.IsDir() {
return nil, errfmt.Errorf("cannot use a path of existing directory %s", path)
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/flags/tracee_ebpf_output.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func TraceeEbpfPrepareOutput(outputSlice []string, newBinary bool) (PrepareOutpu

printerConfigs = append(printerConfigs, stdoutConfig)
} else {
file, err := createFile(outPath)
file, err := CreateOutputFile(outPath)
if err != nil {
return outConfig, err
}
Expand Down

0 comments on commit 77b132d

Please sign in to comment.