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 Dec 5, 2024
1 parent 9193149 commit 010a831
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 23 deletions.
57 changes: 45 additions & 12 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 All @@ -22,13 +23,13 @@ func init() {
analyzeCmd.Flags().String(
"source",
"",
"Cource file to analyze (required). Currently only JSON is supported.",
"Source file to analyze (required). Currently only JSON is supported.",
)

// output
analyzeCmd.Flags().String(
"output",
"stdout:json",
"json:stdout",
"Output destination (file, webhook, fluentbit) and format (json, gotemplate=, table) set as <output_path>:<format>",
)

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

var analyzeCmd = &cobra.Command{
Use: "tracee analyze --input <json_file>",
Use: "analyze [--source 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,47 @@ 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>)")
if len(outputParts) > 2 || len(outputParts) == 0 {
logger.Fatalw("Failed to prepare output format (must be of format <format>:<optional_output_path>)")
}
printerCfg, err := flags.PreparePrinterConfig(outputParts[1], outputParts[0])
if err != nil {
logger.Fatalw("Failed to prepare output configuration", "error", err)

outFormat := outputParts[0]
outPath := ""
if len(outputParts) > 1 {
outPath = outputParts[1]
}
p, err := printer.New(printerCfg)
if err != nil {
logger.Fatalw("Failed to create printer", "error", err)

if outFormat == "legacy" {
if outPath != "stdout" && outPath != "" {
legacyOutFile, err = flags.CreateOutputFile(outPath)
if err != nil {
logger.Fatalw("Failed to create output file for legacy output")
}
}
isLegacy = true
} else {
printerCfg, err := flags.PreparePrinterConfig(outFormat, outPath)
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 +171,8 @@ func command(cmd *cobra.Command, args []string) {
Rego: rego,
Source: sourceFile,
Printer: p,
Legacy: isLegacy,
LegacyOut: legacyOutFile,
SignatureDirs: signatureDirs,
SignatureEvents: signatureEvents,
})
Expand Down
57 changes: 50 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,45 @@ 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)
}

_, err = fmt.Fprintln(outF, string(outBytes))
if err != nil {
logger.Errorw("failed to write legacy output to file", "err", err)
}
}
}

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" && outputPath != "" && 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 010a831

Please sign in to comment.