Skip to content

Commit cbfce9b

Browse files
authored
fix(dropreason): Check ftrace_enabled required for fexit programs (#1926)
# Description Adds a check for `/proc/sys/kernel/ftrace_enabled` before deciding to use fexit eBPF programs. When ftrace is disabled, the plugin will fall back to kprobes. ## Changes - Added `IsFtraceEnabled()` helper function in `pkg/plugin/common/common_linux.go` that reads `/proc/sys/kernel/ftrace_enabled` - Updated `getEbpfPayload()` to check ftrace status and log it - Modified `resolvePayload()` to accept `ftraceEnabled` parameter and only use fexit programs when ftrace is enabled (in addition to existing kernel version/architecture requirements) - Updated documentation to clarify that fexit programs require ftrace to be enabled ## Behavior - **Before**: Plugin would attempt to use fexit programs based only on kernel version and architecture, potentially failing when ftrace is disabled - **After**: Plugin checks ftrace status and gracefully falls back to kprobes when ftrace is disabled ## Related Issue If this pull request is related to any issue, please mention it here. Additionally, make sure that the issue is assigned to you before submitting this pull request. ## Checklist - [x] I have read the [contributing documentation](https://retina.sh/docs/Contributing/overview). - [x] I signed and signed-off the commits (`git commit -S -s ...`). See [this documentation](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification) on signing commits. - [x] I have correctly attributed the author(s) of the code. - [x] I have tested the changes locally. - [x] I have followed the project's style guidelines. - [x] I have updated the documentation, if necessary. - [x] I have added tests, if applicable. ## Screenshots (if applicable) or Testing Completed Verified on kernel 6.6.0 with both ftrace enabled and disabled scenarios. When ftrace is enabled fexit programs are used. When ftrace is disabled, the plugin uses kprobes/kretprobes. <img width="1739" height="677" alt="image" src="https://github.com/user-attachments/assets/39ae49f2-7600-4ab0-aa68-8abd0c6d0472" /> <img width="1743" height="806" alt="image" src="https://github.com/user-attachments/assets/25aef3cf-fc27-4dae-8328-4d4e50d43ca9" /> ## Additional Notes Add any additional notes or context about the pull request here. --- Please refer to the [CONTRIBUTING.md](../CONTRIBUTING.md) file for more information on how to contribute to this project.
1 parent 34e8f5f commit cbfce9b

File tree

4 files changed

+55
-10
lines changed

4 files changed

+55
-10
lines changed

pkg/plugin/common/common_linux.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,13 @@ func readIDField(path string) string {
138138
}
139139
return ""
140140
}
141+
142+
// IsFtraceEnabled checks if ftrace is enabled in the kernel.
143+
// This is required for fexit/fentry programs to work.
144+
func IsFtraceEnabled() bool {
145+
data, err := os.ReadFile("/proc/sys/kernel/ftrace_enabled")
146+
if err != nil {
147+
return false
148+
}
149+
return strings.TrimSpace(string(data)) == "1"
150+
}

pkg/plugin/dropreason/dropreason_linux_test.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ func TestResolveEbpfPayload(t *testing.T) {
484484
kv semver.Version
485485
isMariner bool
486486
isPodLevel bool
487+
ftraceEnabled bool
487488
wantType string
488489
wantSupportsFexit bool
489490
}{
@@ -493,6 +494,7 @@ func TestResolveEbpfPayload(t *testing.T) {
493494
kv: mustVersion("5.4.0"),
494495
isMariner: false,
495496
isPodLevel: false,
497+
ftraceEnabled: true,
496498
wantType: "*dropreason.allKprobeObjects",
497499
wantSupportsFexit: false,
498500
},
@@ -502,6 +504,7 @@ func TestResolveEbpfPayload(t *testing.T) {
502504
kv: mustVersion("5.10.0"),
503505
isMariner: false,
504506
isPodLevel: false,
507+
ftraceEnabled: true,
505508
wantType: "*dropreason.allFexitObjects",
506509
wantSupportsFexit: true,
507510
},
@@ -511,6 +514,7 @@ func TestResolveEbpfPayload(t *testing.T) {
511514
kv: mustVersion("5.10.0"),
512515
isMariner: true,
513516
isPodLevel: false,
517+
ftraceEnabled: true,
514518
wantType: "*dropreason.marinerObjects",
515519
wantSupportsFexit: true,
516520
},
@@ -520,6 +524,7 @@ func TestResolveEbpfPayload(t *testing.T) {
520524
kv: mustVersion("5.8.0"),
521525
isMariner: true,
522526
isPodLevel: false,
527+
ftraceEnabled: true,
523528
wantType: "*dropreason.allKprobeObjects",
524529
wantSupportsFexit: false,
525530
},
@@ -529,6 +534,7 @@ func TestResolveEbpfPayload(t *testing.T) {
529534
kv: mustVersion("6.1.0"),
530535
isMariner: true,
531536
isPodLevel: false,
537+
ftraceEnabled: true,
532538
wantType: "*dropreason.marinerObjects",
533539
wantSupportsFexit: true,
534540
},
@@ -538,14 +544,35 @@ func TestResolveEbpfPayload(t *testing.T) {
538544
kv: mustVersion("5.15.0"),
539545
isMariner: false,
540546
isPodLevel: true,
547+
ftraceEnabled: true,
548+
wantType: "*dropreason.allKprobeObjects",
549+
wantSupportsFexit: false,
550+
},
551+
{
552+
name: "mariner with ftrace disabled - fallback to kprobes",
553+
arch: "amd64",
554+
kv: mustVersion("5.15.0"),
555+
isMariner: true,
556+
isPodLevel: false,
557+
ftraceEnabled: false,
558+
wantType: "*dropreason.allKprobeObjects",
559+
wantSupportsFexit: false,
560+
},
561+
{
562+
name: "ubuntu with ftrace disabled - fallback to kprobes",
563+
arch: "amd64",
564+
kv: mustVersion("6.6.0"),
565+
isMariner: false,
566+
isPodLevel: false,
567+
ftraceEnabled: false,
541568
wantType: "*dropreason.allKprobeObjects",
542569
wantSupportsFexit: false,
543570
},
544571
}
545572

546573
for _, tt := range tests {
547574
t.Run(tt.name, func(t *testing.T) {
548-
objs, _, isFexit := resolvePayload(tt.arch, tt.kv, tt.isMariner, tt.isPodLevel)
575+
objs, _, isFexit := resolvePayload(tt.arch, tt.kv, tt.isMariner, tt.isPodLevel, tt.ftraceEnabled)
549576

550577
if isFexit != tt.wantSupportsFexit {
551578
t.Errorf("isFexit = %v, want %v", isFexit, tt.wantSupportsFexit)

pkg/plugin/dropreason/ebpfsetup_linux.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ eBPF Program Support Matrix
2828
2929
Program Type Selection:
3030
- If:
31+
- Ftrace is enabled AND
3132
- Arch == amd64 and kernel >= 5.5
3233
- Arch == arm64 and kernel >= 6.0
3334
→ Use `fexit`
@@ -44,13 +45,15 @@ Scope Selection:
4445
+-----------+------------------------+--------------+--------+
4546
| Distro | Arch + Kernel | Prog | Scope |
4647
+-----------+------------------------+--------------+--------+
47-
| Mariner | amd64, kernel >= 5.5 | fexit | core |
48-
| Mariner | arm64, kernel >= 6.0 | fexit | core |
49-
| Non-Marin | amd64, kernel >= 5.5 | fexit | all |
50-
| Non-Marin | arm64, kernel >= 6.0 | fexit | all |
48+
| Mariner | amd64, kernel >= 5.5 | fexit* | core |
49+
| Mariner | arm64, kernel >= 6.0 | fexit* | core |
50+
| Non-Marin | amd64, kernel >= 5.5 | fexit* | all |
51+
| Non-Marin | arm64, kernel >= 6.0 | fexit* | all |
5152
| * | (otherwise) | kprobe | per OS |
5253
+-----------+------------------------+--------------+--------+
5354
55+
* fexit requires ftrace to be enabled in the kernel
56+
5457
core kernel funcs:
5558
- tcp_v4_connect
5659
- inet_csk_accept
@@ -74,16 +77,21 @@ func (dr *dropReason) getEbpfPayload() (objs interface{}, maps *kprobeMaps, supp
7477
}
7578
dr.l.Info("Detected kernel", zap.String("version", kv.String()))
7679

77-
objs, maps, supportsFexit = resolvePayload(runtime.GOARCH, kv, isMariner, dr.cfg.EnablePodLevel)
80+
// Check if ftrace is enabled (required for fexit programs)
81+
ftraceEnabled := plugincommon.IsFtraceEnabled()
82+
dr.l.Info("Ftrace status", zap.Bool("enabled", ftraceEnabled))
83+
84+
objs, maps, supportsFexit = resolvePayload(runtime.GOARCH, kv, isMariner, dr.cfg.EnablePodLevel, ftraceEnabled)
7885
return objs, maps, supportsFexit, nil
7986
}
8087

81-
func resolvePayload(arch string, kv semver.Version, isMariner, isPodLevel bool) (interface{}, *kprobeMaps, bool) {
88+
func resolvePayload(arch string, kv semver.Version, isMariner, isPodLevel, ftraceEnabled bool) (interface{}, *kprobeMaps, bool) {
8289
minVersionAmd64, _ := versioncheck.Version(MinAmdVersionNum)
8390
minVersionArm64, _ := versioncheck.Version(MinArmVersionNum)
8491

85-
supportsFexit := (arch == "amd64" && kv.GTE(minVersionAmd64)) ||
86-
(arch == "arm64" && kv.GTE(minVersionArm64))
92+
supportsFexit := ftraceEnabled &&
93+
((arch == "amd64" && kv.GTE(minVersionAmd64)) ||
94+
(arch == "arm64" && kv.GTE(minVersionArm64)))
8795

8896
var objs interface{}
8997
var maps *kprobeMaps

test/plugin/dropreason/main_linux.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func main() {
3030

3131
cfg := &kcfg.Config{
3232
MetricsInterval: 1 * time.Second,
33-
EnablePodLevel: true,
33+
EnablePodLevel: true, // Set to false to test fexit programs
3434
}
3535

3636
// Filtermanager.

0 commit comments

Comments
 (0)