diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-23 19:59:29 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-23 19:59:29 +0300 |
| commit | b4a172404be8b52ed62171dcbbd3e9f46e36ac67 (patch) | |
| tree | c92405f3843b6e743d32b7f899d54b26f6984d31 /internal/tracepoints | |
| parent | 940bd6e00cb28af5f076828f6c90e6f3bc729cd8 (diff) | |
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 <noreply@anthropic.com>
Diffstat (limited to 'internal/tracepoints')
| -rw-r--r-- | internal/tracepoints/dimension_selector.go | 23 | ||||
| -rw-r--r-- | internal/tracepoints/dimension_selector_test.go | 80 |
2 files changed, 103 insertions, 0 deletions
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) + } + } +} |
