diff --git a/pkg/utils/datasource_event.go b/pkg/utils/datasource_event.go index 614a969da..6cde2d340 100644 --- a/pkg/utils/datasource_event.go +++ b/pkg/utils/datasource_event.go @@ -537,7 +537,7 @@ func (e *DatasourceEvent) GetExePath() string { logger.L().Warning("GetExePath - error reading field exepath", helpers.String("eventType", string(e.EventType)), helpers.Error(err)) return "" } - return exepath + return NormalizePath(exepath) } func (e *DatasourceEvent) GetExitCode() uint32 { @@ -579,7 +579,7 @@ func (e *DatasourceEvent) GetFullPath() string { return "" } } - return path + return NormalizePath(path) } func (e *DatasourceEvent) GetGid() *uint32 { @@ -658,7 +658,7 @@ func (e *DatasourceEvent) GetNewPath() string { logger.L().Warning("GetNewPath - error reading field newpath", helpers.String("eventType", string(e.EventType)), helpers.Error(err)) return "" } - return newPath + return NormalizePath(newPath) } func (e *DatasourceEvent) GetNumAnswers() int { @@ -676,7 +676,7 @@ func (e *DatasourceEvent) GetOldPath() string { logger.L().Warning("GetOldPath - error reading field oldpath", helpers.String("eventType", string(e.EventType)), helpers.Error(err)) return "" } - return oldPath + return NormalizePath(oldPath) } func (e *DatasourceEvent) GetOpcode() int { @@ -710,7 +710,7 @@ func (e *DatasourceEvent) GetPath() string { logger.L().Warning("GetPath - error reading field fname", helpers.String("eventType", string(e.EventType)), helpers.Error(err)) return "" } - return path + return NormalizePath(path) } func (e *DatasourceEvent) GetPcomm() string { diff --git a/pkg/utils/normalize_path_test.go b/pkg/utils/normalize_path_test.go new file mode 100644 index 000000000..7ab3a2494 --- /dev/null +++ b/pkg/utils/normalize_path_test.go @@ -0,0 +1,72 @@ +package utils + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestNormalizePath(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + { + name: "empty path", + input: "", + expected: "", + }, + { + name: "dot path", + input: ".", + expected: "/", + }, + { + name: "absolute path", + input: "/etc/passwd", + expected: "/etc/passwd", + }, + { + name: "headless proc path (task)", + input: "/46/task/46/fd", + expected: "/proc/46/task/46/fd", + }, + { + name: "headless proc path (fd)", + input: "/46/fd/3", + expected: "/proc/46/fd/3", + }, + { + name: "already absolute proc path", + input: "/proc/46/fd/3", + expected: "/proc/46/fd/3", + }, + { + name: "relative path (not dot)", + input: "usr/bin/ls", + expected: "/usr/bin/ls", + }, + { + name: "relative path with ./", + input: "./config", + expected: "/config", + }, + { + name: "path with redundant slashes", + input: "/etc//passwd", + expected: "/etc/passwd", + }, + { + name: "path with dot components", + input: "/usr/./bin/../lib", + expected: "/usr/lib", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := NormalizePath(tt.input) + assert.Equal(t, tt.expected, got) + }) + } +} diff --git a/pkg/utils/path.go b/pkg/utils/path.go new file mode 100644 index 000000000..0199ce916 --- /dev/null +++ b/pkg/utils/path.go @@ -0,0 +1,34 @@ +package utils + +import ( + "path" + "regexp" + "strings" +) + +var headlessProcRegex = regexp.MustCompile(`^/\d+/(task|fd)/`) + +// NormalizePath normalizes a path by: +// 1. Prepending "/proc" to "headless" proc paths (e.g. /46/task/46/fd -> /proc/46/task/46/fd) +// 2. Ensuring it starts with "/" if it's not empty +// 3. Converting "." to "/" +// 4. Cleaning the path (removing redundant slashes, dot-dots, etc.) +func NormalizePath(p string) string { + if p == "" { + return "" + } + + if p == "." { + return "/" + } + + if headlessProcRegex.MatchString(p) { + p = "/proc" + p + } + + if !strings.HasPrefix(p, "/") { + p = "/" + p + } + + return path.Clean(p) +}