diff --git a/cmd/tracee/cmd/analyze.go b/cmd/tracee/cmd/analyze.go index 1e82d711f8a4..6f91c297d755 100644 --- a/cmd/tracee/cmd/analyze.go +++ b/cmd/tracee/cmd/analyze.go @@ -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" ) @@ -63,7 +64,7 @@ func init() { } var analyzeCmd = &cobra.Command{ - Use: "tracee analyze --input ", + Use: "tracee analyze --source ", Aliases: []string{}, Short: "Analyze past events with signature events [Experimental]", Long: `Analyze allow you to explore signature events with past events. @@ -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") @@ -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 :)") } - 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 @@ -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, }) diff --git a/pkg/analyze/analyze.go b/pkg/analyze/analyze.go index 56bb8edd3e0f..72ae35a9a374 100644 --- a/pkg/analyze/analyze.go +++ b/pkg/analyze/analyze.go @@ -4,6 +4,7 @@ import ( "bufio" "context" "encoding/json" + "fmt" "os" "os/signal" "syscall" @@ -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 } @@ -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) @@ -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 @@ -118,7 +129,7 @@ drain: return } - process(finding, cfg.Printer) + process(finding) default: return } @@ -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 { diff --git a/pkg/cmd/flags/logger.go b/pkg/cmd/flags/logger.go index d95c8d295253..e811c1e810e6 100644 --- a/pkg/cmd/flags/logger.go +++ b/pkg/cmd/flags/logger.go @@ -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 } diff --git a/pkg/cmd/flags/output.go b/pkg/cmd/flags/output.go index 2e6d0205db43..24142ad26a43 100644 --- a/pkg/cmd/flags/output.go +++ b/pkg/cmd/flags/output.go @@ -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 } @@ -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) diff --git a/pkg/cmd/flags/tracee_ebpf_output.go b/pkg/cmd/flags/tracee_ebpf_output.go index 95a4d5f7957f..e87230a2d7a8 100644 --- a/pkg/cmd/flags/tracee_ebpf_output.go +++ b/pkg/cmd/flags/tracee_ebpf_output.go @@ -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 }