From 8b075eb78615bce1122350adeede16e89b90a309 Mon Sep 17 00:00:00 2001 From: entlein Date: Sat, 1 Aug 2026 16:51:58 +0200 Subject: [PATCH 1/2] addon fix for the old issue to /proc full paths not being recorded Signed-off-by: entlein --- pkg/utils/normalize_path_test.go | 24 ++++++++++++++++++++++++ pkg/utils/path.go | 11 ++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/pkg/utils/normalize_path_test.go b/pkg/utils/normalize_path_test.go index 32d5e300c..c3829b79c 100644 --- a/pkg/utils/normalize_path_test.go +++ b/pkg/utils/normalize_path_test.go @@ -50,6 +50,30 @@ func TestNormalizePath(t *testing.T) { input: "/46/task", expected: "/proc/46/task", }, + { + // #721 regression: runc:[2:INIT] user-namespace-setup paths outside + // the old (task|fd) allowlist previously leaked /proc-less. + name: "headless proc path (setgroups)", + input: "/17/setgroups", + expected: "/proc/17/setgroups", + }, + { + name: "headless proc path (gid_map)", + input: "/1/gid_map", + expected: "/proc/1/gid_map", + }, + { + name: "headless proc path (uid_map)", + input: "/1/uid_map", + expected: "/proc/1/uid_map", + }, + { + // A non-proc path whose leading segment is non-numeric must be + // untouched even though a later segment looks proc-like. + name: "non-proc path with data dir", + input: "/data/appendonlydir/x", + expected: "/data/appendonlydir/x", + }, { name: "relative path (not dot)", input: "usr/bin/ls", diff --git a/pkg/utils/path.go b/pkg/utils/path.go index 9a9fcd481..3999f4ad8 100644 --- a/pkg/utils/path.go +++ b/pkg/utils/path.go @@ -6,7 +6,16 @@ import ( "strings" ) -var headlessProcRegex = regexp.MustCompile(`^/\d+/(task|fd)(/|$)`) +// headlessProcRegex matches any path whose leading segment is a bare PID — the +// residue of a /proc//... path stripped of its /proc root. A top-level +// numeric segment is never a real filesystem path node-agent should record, so +// the entire class is normalized back under /proc. +// +// The allowlist was previously narrowed to `(task|fd)`, which let sibling +// headless paths written by runc:[2:INIT] during user-namespace setup — +// //setgroups, //gid_map, //uid_map, //status, //cgroup, +// ... — leak /proc-less into learned ContainerProfiles (a regression of #721). +var headlessProcRegex = regexp.MustCompile(`^/\d+(/|$)`) // NormalizePath normalizes a path by: // 1. Prepending "/proc" to "headless" proc paths (e.g. /46/task/46/fd -> /proc/46/task/46/fd) From d48b8f447281a9a0e6b183e72dcde7a9a4ed2ad5 Mon Sep 17 00:00:00 2001 From: entlein Date: Sat, 1 Aug 2026 17:05:36 +0200 Subject: [PATCH 2/2] that regex was too narrow, adding the obvious ones, but might need to RCA why this regressed in the first place Signed-off-by: entlein --- pkg/utils/path.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/pkg/utils/path.go b/pkg/utils/path.go index 3999f4ad8..041eb3c97 100644 --- a/pkg/utils/path.go +++ b/pkg/utils/path.go @@ -6,16 +6,17 @@ import ( "strings" ) -// headlessProcRegex matches any path whose leading segment is a bare PID — the -// residue of a /proc//... path stripped of its /proc root. A top-level -// numeric segment is never a real filesystem path node-agent should record, so -// the entire class is normalized back under /proc. +// headlessProcRegex matches a headless /proc// path — a /proc//... +// path stripped of its /proc root — which NormalizePath re-roots under /proc. // -// The allowlist was previously narrowed to `(task|fd)`, which let sibling -// headless paths written by runc:[2:INIT] during user-namespace setup — -// //setgroups, //gid_map, //uid_map, //status, //cgroup, -// ... — leak /proc-less into learned ContainerProfiles (a regression of #721). -var headlessProcRegex = regexp.MustCompile(`^/\d+(/|$)`) +// The allowlist enumerates the /proc/ entries opened by runc:[2:INIT] +// during container/user-namespace setup. It was previously only (task|fd), +// which let the sibling entries (setgroups, gid_map, uid_map, status, cgroup, +// ...) leak /proc-less into learned ContainerProfiles — a regression of #721. +// It stays an explicit allowlist rather than a bare `^/\d+` catch-all so a +// genuine top-level numeric directory is never misread as a PID; extend it if +// another /proc/ entry is observed leaking. +var headlessProcRegex = regexp.MustCompile(`^/\d+/(task|fd|setgroups|gid_map|uid_map|status|stat|cgroup|mountinfo|maps|environ|comm|cmdline|ns)(/|$)`) // NormalizePath normalizes a path by: // 1. Prepending "/proc" to "headless" proc paths (e.g. /46/task/46/fd -> /proc/46/task/46/fd)