Skip to content

Commit

Permalink
usm: file registry: Save block reason
Browse files Browse the repository at this point in the history
When we block a path, save the reason and expose it via the debug
endpoint, as a debugging aid. For common errors such as "not a Go
program", we save a summary instead of the full error message to reduce
memory usage.
  • Loading branch information
vitkyrka committed Dec 23, 2024
1 parent 68a6fd3 commit 6b54dd6
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 5 deletions.
6 changes: 4 additions & 2 deletions pkg/network/usm/utils/debugger.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type BlockedProcess struct {
type PathIdentifierWithSamplePath struct {
PathIdentifier
SamplePath string
Reason string
}

// GetTracedProgramsEndpoint returns a callback for the given module name, that
Expand Down Expand Up @@ -213,11 +214,12 @@ func (d *tlsDebugger) GetBlockedPathIDsWithSamplePath(moduleName, programType st

blockedIDsWithSampleFile := make([]PathIdentifierWithSamplePath, 0, len(registry.blocklistByID.Keys()))
for _, pathIdentifier := range registry.blocklistByID.Keys() {
samplePath, ok := registry.blocklistByID.Get(pathIdentifier)
entry, ok := registry.blocklistByID.Get(pathIdentifier)
if ok {
blockedIDsWithSampleFile = append(blockedIDsWithSampleFile, PathIdentifierWithSamplePath{
PathIdentifier: pathIdentifier,
SamplePath: samplePath})
SamplePath: entry.Path,
Reason: entry.Reason})
}
}

Expand Down
30 changes: 27 additions & 3 deletions pkg/network/usm/utils/file_registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ import (
"github.com/hashicorp/golang-lru/v2/simplelru"
"go.uber.org/atomic"

"github.com/DataDog/datadog-agent/pkg/network/go/binversion"
"github.com/DataDog/datadog-agent/pkg/network/protocols/telemetry"
"github.com/DataDog/datadog-agent/pkg/util/kernel"
"github.com/DataDog/datadog-agent/pkg/util/log"
"github.com/DataDog/datadog-agent/pkg/util/safeelf"
)

// FileRegistry is responsible for tracking open files and executing callbacks
Expand Down Expand Up @@ -48,11 +50,17 @@ type FileRegistry struct {
byPID map[uint32]pathIdentifierSet

// if we can't execute a callback for a given file we don't try more than once
blocklistByID *simplelru.LRU[PathIdentifier, string]
blocklistByID *simplelru.LRU[PathIdentifier, BlockListEntry]

telemetry registryTelemetry
}

// BlockListEntry represents an enty in the block list
type BlockListEntry struct {
Path string
Reason string
}

// FilePath represents the location of a file from the *root* namespace view
type FilePath struct {
HostPath string
Expand Down Expand Up @@ -90,7 +98,7 @@ var ErrEnvironment = errors.New("Environment error, path will not be blocked")

// NewFileRegistry creates a new `FileRegistry` instance
func NewFileRegistry(moduleName, programName string) *FileRegistry {
blocklistByID, err := simplelru.NewLRU[PathIdentifier, string](2000, nil)
blocklistByID, err := simplelru.NewLRU[PathIdentifier, BlockListEntry](2000, nil)
if err != nil {
log.Warnf("running without block cache list, creation error: %s", err)
blocklistByID = nil
Expand Down Expand Up @@ -121,6 +129,22 @@ var (
ErrPathIsAlreadyRegistered = errors.New("path is already registered")
)

// getBlockReason creates a string specifying the reason for the block based on
// the error received. To reduce memory usage of this debugging feature, for
// very common errors we store a summary instead of the full error string,
// leaving the latter for more interesting errors.
func getBlockReason(error error) string {
if errors.Is(error, binversion.ErrNotGoExe) {
return "not-go"
}

if errors.Is(error, safeelf.ErrNoSymbols) {
return "no-symbols"
}

return error.Error()
}

// Register inserts or updates a new file registration within to the `FileRegistry`;
//
// If no current registration exists for the given `PathIdentifier`, we execute
Expand Down Expand Up @@ -193,7 +217,7 @@ func (r *FileRegistry) Register(namespacedPath string, pid uint32, activationCB,
if r.blocklistByID != nil {
// add `pathID` to blocklist so we don't attempt to re-register files
// that are problematic for some reason
r.blocklistByID.Add(pathID, path.HostPath)
r.blocklistByID.Add(pathID, BlockListEntry{Path: path.HostPath, Reason: getBlockReason(err)})
}
r.telemetry.fileHookFailed.Add(1)
return err
Expand Down
3 changes: 3 additions & 0 deletions pkg/network/usm/utils/file_registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ func TestFailedRegistration(t *testing.T) {
assert.Equal(t, 1, registerRecorder.CallsForPathID(pathID))

assert.Contains(t, debugger.GetBlockedPathIDs(testModuleName, ""), pathID)
info := debugger.GetBlockedPathIDsWithSamplePath(testModuleName, "")
require.Len(t, info, 1)
assert.Equal(t, registerRecorder.ReturnError.Error(), info[0].Reason)
debugger.ClearBlocked(testModuleName)
assert.Empty(t, debugger.GetBlockedPathIDs(testModuleName, ""))
}
Expand Down

0 comments on commit 6b54dd6

Please sign in to comment.