Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 14 additions & 13 deletions cmd/cve/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package main

import (
"compress/gzip"
"context"
"crypto/sha256"
"encoding/hex"
"flag"
"fmt"
"io"
"log/slog"
"net/http"
"os"
"path/filepath"
Expand All @@ -17,8 +19,6 @@ import (
"github.com/fleetdm/fleet/v4/pkg/fleethttp"
"github.com/fleetdm/fleet/v4/server/vulnerabilities/nvd"
nvdsync "github.com/fleetdm/fleet/v4/server/vulnerabilities/nvd/sync"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
)

const emptyData = `{
Expand All @@ -37,19 +37,20 @@ func main() {
debug := flag.Bool("debug", false, "Sets debug mode")
flag.Parse()

logger := log.NewJSONLogger(os.Stdout)
ctx := context.Background()

logLevel := slog.LevelInfo
if *debug {
logger = level.NewFilter(logger, level.AllowDebug())
} else {
logger = level.NewFilter(logger, level.AllowInfo())
logLevel = slog.LevelDebug
}
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: logLevel}))

if err := os.MkdirAll(*dbDir, os.ModePerm); err != nil {
panic(err)
}

if os.Getenv(cleanEnvVar) == "false" {
logger.Log("msg", "Downloading latest release")
logger.InfoContext(ctx, "Downloading latest release")
maxRetries := 3
for i := 0; i < maxRetries; i++ {
err := downloadLatestRelease(*dbDir, *debug, logger)
Expand All @@ -58,11 +59,11 @@ func main() {
}

if i == maxRetries-1 {
logger.Log("msg", "Failed to download latest release. Continuing with full NVD Sync", "err", err)
logger.WarnContext(ctx, "Failed to download latest release. Continuing with full NVD Sync", "err", err)
break
}

logger.Log("msg", "Failed to download latest release. Retrying in 30 seconds", "err", err)
logger.WarnContext(ctx, "Failed to download latest release. Retrying in 30 seconds", "err", err)
time.Sleep(30 * time.Second)
}
}
Expand All @@ -74,12 +75,12 @@ func main() {

// Remove Vulncheck archive
if err := os.RemoveAll(filepath.Join(*dbDir, "vulncheck.zip")); err != nil {
logger.Log("msg", "Failed to remove vulncheck.zip", "err", err)
logger.WarnContext(ctx, "Failed to remove vulncheck.zip", "err", err)
}

// Read in every cpe file and create a corresponding metadata file
// nvd data feeds start in 2002
logger.Log("msg", "Generating metadata files ...")
logger.InfoContext(ctx, "Generating metadata files ...")
const startingYear = 2002
currentYear := time.Now().Year()
if currentYear < startingYear {
Expand All @@ -94,7 +95,7 @@ func main() {
metaName := filepath.Join(*dbDir, fileFmt(suffix, "meta", ""))
// skip if file does not exist
if _, err := os.Stat(fileNameRaw); os.IsNotExist(err) {
logger.Log("msg", "Skipping metadata generation for missing file", "file", fileNameRaw)
logger.InfoContext(ctx, "Skipping metadata generation for missing file", "file", fileNameRaw)
continue
}
err := nvdsync.CompressFile(fileNameRaw, fileName)
Expand All @@ -109,7 +110,7 @@ func main() {
createEmptyFiles(*dbDir, "recent")
}

func downloadLatestRelease(dbDir string, debug bool, logger log.Logger) error {
func downloadLatestRelease(dbDir string, debug bool, logger *slog.Logger) error {
// Download the latest release
err := nvd.DownloadCVEFeed(dbDir, "", debug, logger)
if err != nil {
Expand Down
15 changes: 7 additions & 8 deletions cmd/cve/validate/main.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package main

import (
"context"
"errors"
"flag"
"fmt"
"log/slog"
"os"
"path/filepath"
"strings"
Expand All @@ -14,30 +16,27 @@ import (
"github.com/fleetdm/fleet/v4/server/vulnerabilities/nvd/tools/cvefeed"
feednvd "github.com/fleetdm/fleet/v4/server/vulnerabilities/nvd/tools/cvefeed/nvd"
"github.com/fleetdm/fleet/v4/server/vulnerabilities/oval"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
)

func main() {
dbDir := flag.String("db_dir", "/tmp/vulndbs", "Path to the vulnerability database")
debug := flag.Bool("debug", false, "Sets debug mode")
flag.Parse()

logger := log.NewJSONLogger(os.Stdout)
logLevel := slog.LevelInfo
if *debug {
logger = level.NewFilter(logger, level.AllowDebug())
} else {
logger = level.NewFilter(logger, level.AllowInfo())
logLevel = slog.LevelDebug
}
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: logLevel}))

vulnPath := *dbDir
checkNVDVulnerabilities(vulnPath, logger)
checkGovalDictionaryVulnerabilities(vulnPath)
}

func checkNVDVulnerabilities(vulnPath string, logger log.Logger) {
func checkNVDVulnerabilities(vulnPath string, logger *slog.Logger) {
metaMap := make(map[string]fleet.CVEMeta)
if err := nvd.CVEMetaFromNVDFeedFiles(metaMap, vulnPath, logger); err != nil {
if err := nvd.CVEMetaFromNVDFeedFiles(context.Background(), metaMap, vulnPath, logger); err != nil {
panic(err)
}

Expand Down
16 changes: 8 additions & 8 deletions cmd/fleet/cron.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ func checkCustomVulnerabilities(
ctx, span := tracer.Start(ctx, "vuln.check_custom")
defer span.End()

vulns, err := customcve.CheckCustomVulnerabilities(ctx, ds, logger, startTime)
vulns, err := customcve.CheckCustomVulnerabilities(ctx, ds, logger.SlogLogger(), startTime)
if err != nil {
errHandler(ctx, logger, "checking custom vulnerabilities", err)
}
Expand Down Expand Up @@ -352,7 +352,7 @@ func checkWinVulnerabilities(
}

start := time.Now()
r, err := msrc.Analyze(analyzeCtx, ds, o, vulnPath, collectVulns, logger)
r, err := msrc.Analyze(analyzeCtx, ds, o, vulnPath, collectVulns, logger.SlogLogger())
elapsed := time.Since(start)
level.Debug(logger).Log(
"msg", "msrc-analysis-done",
Expand Down Expand Up @@ -455,7 +455,7 @@ func checkGovalDictionaryVulnerabilities(
if !config.DisableDataSync {
// Sync on disk goval_dictionary sqlite with current OS Versions.
refreshCtx, refreshSpan := tracer.Start(ctx, "vuln.goval_dictionary.refresh")
downloaded, err := goval_dictionary.Refresh(versions, vulnPath, logger)
downloaded, err := goval_dictionary.Refresh(refreshCtx, versions, vulnPath, logger.SlogLogger())
if err != nil {
errHandler(refreshCtx, logger, "updating goval_dictionary databases", err)
}
Expand All @@ -470,7 +470,7 @@ func checkGovalDictionaryVulnerabilities(
trace.WithAttributes(attribute.Int("os_count", len(versions.OSVersions))))
for _, version := range versions.OSVersions {
start := time.Now()
r, err := goval_dictionary.Analyze(analyzeCtx, ds, version, vulnPath, collectVulns, logger)
r, err := goval_dictionary.Analyze(analyzeCtx, ds, version, vulnPath, collectVulns, logger.SlogLogger())
if err != nil && errors.Is(err, goval_dictionary.ErrUnsupportedPlatform) {
level.Debug(logger).Log("msg", "goval_dictionary-analysis-unsupported", "platform", version.Name)
continue
Expand Down Expand Up @@ -512,7 +512,7 @@ func checkNVDVulnerabilities(
CVEFeedPrefixURL: config.CVEFeedPrefixURL,
CISAKnownExploitsURL: config.CISAKnownExploitsURL,
}
err := nvd.Sync(opts, logger)
err := nvd.Sync(syncCtx, opts, logger.SlogLogger())
if err != nil {
errHandler(syncCtx, logger, "syncing vulnerability database", err)
// don't return, continue on ...
Expand All @@ -521,14 +521,14 @@ func checkNVDVulnerabilities(
}

loadCtx, loadSpan := tracer.Start(ctx, "vuln.nvd.load_cve_meta")
if err := nvd.LoadCVEMeta(loadCtx, logger, vulnPath, ds); err != nil {
if err := nvd.LoadCVEMeta(loadCtx, logger.SlogLogger(), vulnPath, ds); err != nil {
errHandler(loadCtx, logger, "load cve meta", err)
// don't return, continue on ...
}
loadSpan.End()

cpeCtx, cpeSpan := tracer.Start(ctx, "vuln.nvd.translate_software_to_cpe")
err := nvd.TranslateSoftwareToCPE(cpeCtx, ds, vulnPath, logger)
err := nvd.TranslateSoftwareToCPE(cpeCtx, ds, vulnPath, logger.SlogLogger())
if err != nil {
errHandler(cpeCtx, logger, "analyzing vulnerable software: Software->CPE", err)
cpeSpan.End()
Expand All @@ -537,7 +537,7 @@ func checkNVDVulnerabilities(
cpeSpan.End()

cveCtx, cveSpan := tracer.Start(ctx, "vuln.nvd.translate_cpe_to_cve")
vulns, err := nvd.TranslateCPEToCVE(cveCtx, ds, vulnPath, logger, collectVulns, startTime)
vulns, err := nvd.TranslateCPEToCVE(cveCtx, ds, vulnPath, logger.SlogLogger(), collectVulns, startTime)
if err != nil {
errHandler(cveCtx, logger, "analyzing vulnerable software: CPE->CVE", err)
cveSpan.End()
Expand Down
4 changes: 2 additions & 2 deletions cmd/fleetctl/fleetctl/vulnerability_data_stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import (
"context"
"errors"
"fmt"
"log/slog"
"os"

"github.com/fleetdm/fleet/v4/server/vulnerabilities/macoffice"
"github.com/fleetdm/fleet/v4/server/vulnerabilities/msrc"
"github.com/fleetdm/fleet/v4/server/vulnerabilities/nvd"
"github.com/fleetdm/fleet/v4/server/vulnerabilities/oval"
klog "github.com/go-kit/log"
"github.com/urfave/cli/v2"
)

Expand Down Expand Up @@ -60,7 +60,7 @@ Downloads (if needed) the data streams that can be used by the Fleet server to p
log(c, " Done\n")

log(c, "[-] Downloading NVD CVE feed...")
err = nvd.DownloadCVEFeed(dir, "", false, klog.NewNopLogger())
err = nvd.DownloadCVEFeed(dir, "", false, slog.New(slog.DiscardHandler))
if err != nil {
return fmt.Errorf("Error downloading NVD CVE feed: %v", err)
}
Expand Down
11 changes: 5 additions & 6 deletions server/vulnerabilities/customcve/matching_rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import (
"context"
"errors"
"fmt"
"log/slog"
"strings"
"time"

"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/vulnerabilities/nvd/tools/cvefeed/nvd"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
)

var (
Expand Down Expand Up @@ -154,7 +153,7 @@ func (r CVEMatchingRules) ValidateAll() error {
}

// CheckCustomVulnerabilities matches software against custom rules and inserts vulnerabilities
func CheckCustomVulnerabilities(ctx context.Context, ds fleet.Datastore, logger log.Logger, startTime time.Time) ([]fleet.SoftwareVulnerability, error) {
func CheckCustomVulnerabilities(ctx context.Context, ds fleet.Datastore, logger *slog.Logger, startTime time.Time) ([]fleet.SoftwareVulnerability, error) {
rules := getCVEMatchingRules()
if err := rules.ValidateAll(); err != nil {
return nil, fmt.Errorf("invalid rules: %w", err)
Expand All @@ -164,7 +163,7 @@ func CheckCustomVulnerabilities(ctx context.Context, ds fleet.Datastore, logger
for i, rule := range rules {
v, err := rule.match(ctx, ds)
if err != nil {
level.Error(logger).Log("msg", "Error matching rule", "ruleIndex", i, "err", err)
logger.ErrorContext(ctx, "Error matching rule", "ruleIndex", i, "err", err)
continue
}
vulns = append(vulns, v...)
Expand All @@ -174,12 +173,12 @@ func CheckCustomVulnerabilities(ctx context.Context, ds fleet.Datastore, logger
if err != nil {
// Return early so DeleteOutOfDateVulnerabilities doesn't run.
// Otherwise, without the insert refreshing updated_at, all existing vulns would look stale and be deleted.
level.Error(logger).Log("msg", "Error inserting software vulnerabilities", "err", err)
logger.ErrorContext(ctx, "Error inserting software vulnerabilities", "err", err)
return nil, err
}

if err := ds.DeleteOutOfDateVulnerabilities(ctx, fleet.CustomSource, startTime); err != nil {
level.Error(logger).Log("msg", "Error deleting out of date vulnerabilities", "err", err)
logger.ErrorContext(ctx, "Error deleting out of date vulnerabilities", "err", err)
}

return newVulns, nil
Expand Down
6 changes: 3 additions & 3 deletions server/vulnerabilities/customcve/matching_rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package customcve

import (
"context"
"log/slog"
"sort"
"testing"
"time"

"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/mock"
"github.com/fleetdm/fleet/v4/server/ptr"
"github.com/go-kit/log"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -353,7 +353,7 @@ func TestCheckCustomVulnerabilities(t *testing.T) {
}

ctx := context.Background()
vulns, err := CheckCustomVulnerabilities(ctx, ds, log.NewNopLogger(), time.Now().UTC().Add(-time.Hour))
vulns, err := CheckCustomVulnerabilities(ctx, ds, slog.New(slog.DiscardHandler), time.Now().UTC().Add(-time.Hour))
require.NoError(t, err)
require.Len(t, vulns, 35)
require.True(t, ds.DeleteOutOfDateVulnerabilitiesFuncInvoked)
Expand Down Expand Up @@ -583,7 +583,7 @@ func TestCheckCustomVulnerabilities(t *testing.T) {
}

ctx := t.Context()
vulns, err := CheckCustomVulnerabilities(ctx, ds, log.NewNopLogger(), time.Now().UTC().Add(-time.Hour))
vulns, err := CheckCustomVulnerabilities(ctx, ds, slog.New(slog.DiscardHandler), time.Now().UTC().Add(-time.Hour))
require.NoError(t, err)
require.True(t, ds.DeleteOutOfDateVulnerabilitiesFuncInvoked)
require.Len(t, vulns, 0)
Expand Down
6 changes: 3 additions & 3 deletions server/vulnerabilities/goval_dictionary/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import (
"database/sql"
"errors"
"fmt"
"log/slog"

"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/vulnerabilities/oval"
"github.com/fleetdm/fleet/v4/server/vulnerabilities/utils"
kitlog "github.com/go-kit/log"
)

const (
Expand All @@ -28,7 +28,7 @@ func Analyze(
ver fleet.OSVersion,
vulnPath string,
collectVulns bool,
logger kitlog.Logger,
logger *slog.Logger,
) ([]fleet.SoftwareVulnerability, error) {
platform := oval.NewPlatform(ver.Platform, ver.Name)
source := fleet.GovalDictionarySource
Expand Down Expand Up @@ -74,7 +74,7 @@ func Analyze(
return nil, err
}

vulnerabilities := db.Eval(software, logger)
vulnerabilities := db.Eval(ctx, software, logger)
foundInBatch[hostID] = vulnerabilities
}

Expand Down
12 changes: 5 additions & 7 deletions server/vulnerabilities/goval_dictionary/database.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package goval_dictionary

import (
"context"
"database/sql"
"fmt"
"log/slog"
"strings"

"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/vulnerabilities/oval"
"github.com/fleetdm/fleet/v4/server/vulnerabilities/utils"
kitlog "github.com/go-kit/log"
"github.com/go-kit/log/level"
)

func NewDB(db *sql.DB, platform oval.Platform) *Database {
Expand Down Expand Up @@ -43,7 +43,7 @@ func (db Database) Verfiy() error {

// Eval evaluates the current goval_dictionary database against an OS version and a list of installed software,
// returns all software vulnerabilities found. Logs on any errors so we return as many vulnerabilities as we can.
func (db Database) Eval(software []fleet.Software, logger kitlog.Logger) []fleet.SoftwareVulnerability {
func (db Database) Eval(ctx context.Context, software []fleet.Software, logger *slog.Logger) []fleet.SoftwareVulnerability {
searchStmt := fmt.Sprintf("%s WHERE packages.name = ? AND packages.arch = ? ORDER BY cve_id, version", baseSearchStmt)
vulnerabilities := make([]fleet.SoftwareVulnerability, 0)

Expand All @@ -57,8 +57,7 @@ func (db Database) Eval(software []fleet.Software, logger kitlog.Logger) []fleet
for affectedSoftwareRows.Next() {
var fixedVersionWithEpochPrefix, cve string
if err := affectedSoftwareRows.Scan(&fixedVersionWithEpochPrefix, &cve); err != nil {
level.Error(logger).Log(
"msg", "could not read package vulnerability result",
logger.ErrorContext(ctx, "could not read package vulnerability result",
"package", swItem.Name,
"arch", swItem.Arch,
"platform", db.platform,
Expand Down Expand Up @@ -91,8 +90,7 @@ func (db Database) Eval(software []fleet.Software, logger kitlog.Logger) []fleet
return nil
}()
if err != nil {
level.Error(logger).Log(
"msg", "could not read package vulnerabilities",
logger.ErrorContext(ctx, "could not read package vulnerabilities",
"package", swItem.Name,
"arch", swItem.Arch,
"platform", db.platform,
Expand Down
Loading
Loading