From b4a172404be8b52ed62171dcbbd3e9f46e36ac67 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 23 May 2026 19:59:29 +0300 Subject: zb restore legacy -tps regex selection for non-FS tracepoints When -tps provides an explicit regex but no -trace-* dimension selectors are given, skip the implicit FS-only syscall allowlist so that non-FS tracepoints (e.g. nanosleep) matched by the regex are still attached. Co-Authored-By: Claude Opus 4.7 --- internal/tracepoints/dimension_selector.go | 23 +++++++ internal/tracepoints/dimension_selector_test.go | 80 +++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/internal/tracepoints/dimension_selector.go b/internal/tracepoints/dimension_selector.go index 22a70fb..0ff32b3 100644 --- a/internal/tracepoints/dimension_selector.go +++ b/internal/tracepoints/dimension_selector.go @@ -19,14 +19,37 @@ type DimensionSelectorConfig struct { NoTraceSyscalls string } +// hasAnySelector reports whether any positive or negative dimension selector +// field is populated. When all fields are empty the caller provided no +// -trace-* / -no-trace-* flags. +func (d DimensionSelectorConfig) hasAnySelector() bool { + return d.TraceFamilies != "" || + d.TraceKinds != "" || + d.TraceSyscalls != "" || + d.NoTraceFamilies != "" || + d.NoTraceKinds != "" || + d.NoTraceSyscalls != "" +} + // ParseSelectorWithDimensions compiles regex-based attach/exclude filters and // applies attach-time syscall dimension gating. +// +// Legacy semantics: when the caller supplies an explicit -tps regex but no +// -trace-* / -no-trace-* dimension selectors, the syscall allowlist is skipped +// entirely so that non-FS tracepoints matched by the regex are still attached. func ParseSelectorWithDimensions(attach, exclude string, dims DimensionSelectorConfig) (Selector, error) { sel, err := ParseSelector(attach, exclude) if err != nil { return Selector{}, err } + // When an explicit -tps regex is provided without any dimension selectors, + // preserve legacy behaviour: the regex alone controls attachment and the + // implicit FS-only default is not applied. + if attach != "" && !dims.hasAnySelector() { + return sel, nil + } + allow, err := buildAllowedSyscalls(dims) if err != nil { return Selector{}, err diff --git a/internal/tracepoints/dimension_selector_test.go b/internal/tracepoints/dimension_selector_test.go index 01d48e7..39e24d6 100644 --- a/internal/tracepoints/dimension_selector_test.go +++ b/internal/tracepoints/dimension_selector_test.go @@ -313,3 +313,83 @@ func TestParseSelectorWithDimensionsRejectsInvalidSyscall(t *testing.T) { t.Fatalf("unexpected error: %v", err) } } + +func TestParseSelectorWithDimensionsRegexOnlyNanosleep(t *testing.T) { + // Regression: when -tps provides an explicit regex and no -trace-* + // dimension selectors are given, the implicit FS-only allowlist must not + // reject non-FS tracepoints such as nanosleep. Legacy regex-only + // semantics should let the regex control attachment. + sel, err := ParseSelectorWithDimensions( + "^sys_enter_nanosleep$,^sys_exit_nanosleep$", "", + DimensionSelectorConfig{}, + ) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !sel.ShouldAttach("sys_enter_nanosleep") { + t.Fatal("expected sys_enter_nanosleep to be attached by regex-only selector") + } + if !sel.ShouldAttach("sys_exit_nanosleep") { + t.Fatal("expected sys_exit_nanosleep to be attached by regex-only selector") + } + if sel.ShouldAttach("sys_enter_openat") { + t.Fatal("expected openat to be excluded by regex-only selector") + } +} + +func TestParseSelectorWithDimensionsRegexPlusDimensionStillRestricts(t *testing.T) { + // When both a -tps regex and dimension selectors are provided, the + // dimension allowlist must still be enforced alongside the regex. + sel, err := ParseSelectorWithDimensions( + "^sys_enter_nanosleep$,^sys_exit_nanosleep$", "", + DimensionSelectorConfig{TraceFamilies: "Time"}, + ) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !sel.ShouldAttach("sys_enter_nanosleep") { + t.Fatal("expected nanosleep to pass both regex and Time family filter") + } + if sel.ShouldAttach("sys_enter_openat") { + t.Fatal("expected openat to be excluded by regex filter") + } +} + +func TestParseSelectorWithDimensionsRegexOnlyExcludeStillWorks(t *testing.T) { + // When -tps is set with -tpsExclude but no dimension selectors, the + // exclude regex must still take effect. + sel, err := ParseSelectorWithDimensions( + "nanosleep", "sys_exit_nanosleep", + DimensionSelectorConfig{}, + ) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !sel.ShouldAttach("sys_enter_nanosleep") { + t.Fatal("expected sys_enter_nanosleep to be attached") + } + if sel.ShouldAttach("sys_exit_nanosleep") { + t.Fatal("expected sys_exit_nanosleep to be excluded by -tpsExclude regex") + } +} + +func TestDimensionSelectorConfigHasAnySelector(t *testing.T) { + // Empty config has no selectors. + if (DimensionSelectorConfig{}).hasAnySelector() { + t.Fatal("expected empty config to report no selectors") + } + // Each individual field should count as a selector. + fields := []DimensionSelectorConfig{ + {TraceFamilies: "FS"}, + {TraceKinds: "sleep"}, + {TraceSyscalls: "openat"}, + {NoTraceFamilies: "FS"}, + {NoTraceKinds: "sleep"}, + {NoTraceSyscalls: "openat"}, + } + for _, cfg := range fields { + if !cfg.hasAnySelector() { + t.Fatalf("expected config %+v to report selectors present", cfg) + } + } +} -- cgit v1.2.3