diff --git a/pkg/internal/ebpf/common/common.go b/pkg/internal/ebpf/common/common.go index e2821abb1..6cd1e0f44 100644 --- a/pkg/internal/ebpf/common/common.go +++ b/pkg/internal/ebpf/common/common.go @@ -1,9 +1,13 @@ package ebpfcommon import ( + "bufio" "bytes" "encoding/binary" "io" + "log/slog" + "os" + "strings" "time" "github.com/cilium/ebpf" @@ -68,6 +72,8 @@ type Filter struct { Fd int } +func ptlog() *slog.Logger { return slog.With("component", "ebpf.ProcessTracer") } + func ReadHTTPRequestTraceAsSpan(record *ringbuf.Record) (request.Span, bool, error) { var eventType uint8 @@ -99,3 +105,49 @@ func ReadSQLRequestTraceAsSpan(record *ringbuf.Record) (request.Span, bool, erro return SQLRequestTraceToSpan(&event), false, nil } + +type KernelLockdown uint8 + +const ( + KernelLockdownNone KernelLockdown = iota + 1 + KernelLockdownIntegrity + KernelLockdownConfidentiality + KernelLockdownOther +) + +// Injectable for tests +var lockdownPath = "/sys/kernel/security/lockdown" + +func KernelLockdownMode() KernelLockdown { + plog := ptlog() + plog.Debug("checking kernel lockdown mode, [none] allows us to propagate trace context") + // If we can't find the file, assume no lockdown + if _, err := os.Stat(lockdownPath); err == nil { + f, err := os.Open(lockdownPath) + + if err != nil { + plog.Warn("failed to open /sys/kernel/security/lockdown, assuming lockdown [integrity]", "error", err) + return KernelLockdownIntegrity + } + + defer f.Close() + scanner := bufio.NewScanner(f) + if scanner.Scan() { + lockdown := scanner.Text() + if strings.Contains(lockdown, "[none]") { + return KernelLockdownNone + } else if strings.Contains(lockdown, "[integrity]") { + return KernelLockdownIntegrity + } else if strings.Contains(lockdown, "[confidentiality]") { + return KernelLockdownConfidentiality + } + return KernelLockdownOther + } + + plog.Warn("file /sys/kernel/security/lockdown is empty, assuming lockdown [integrity]") + return KernelLockdownIntegrity + } + + plog.Debug("can't find /sys/kernel/security/lockdown, assuming no lockdown") + return KernelLockdownNone +} diff --git a/pkg/internal/ebpf/common/common_test.go b/pkg/internal/ebpf/common/common_test.go new file mode 100644 index 000000000..51a84893e --- /dev/null +++ b/pkg/internal/ebpf/common/common_test.go @@ -0,0 +1,61 @@ +package ebpfcommon + +import ( + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" +) + +func setIntegrity(t *testing.T, path, text string) { + err := os.WriteFile(path, []byte(text), 0644) + assert.NoError(t, err) +} + +func setNotReadable(t *testing.T, path string) { + err := os.Chmod(path, 000) + assert.NoError(t, err) +} + +func TestLockdownParsing(t *testing.T) { + noFile, err := os.CreateTemp("", "not_existent_fake_lockdown") + assert.NoError(t, err) + notPath, err := filepath.Abs(noFile.Name()) + assert.NoError(t, err) + noFile.Close() + os.Remove(noFile.Name()) + + // Setup for testing file that doesn't exist + lockdownPath = notPath + assert.Equal(t, KernelLockdownNone, KernelLockdownMode()) + + tempFile, err := os.CreateTemp("", "fake_lockdown") + assert.NoError(t, err) + path, err := filepath.Abs(tempFile.Name()) + assert.NoError(t, err) + tempFile.Close() + + defer os.Remove(tempFile.Name()) + // Setup for testing + lockdownPath = path + + setIntegrity(t, path, "none [integrity] confidentiality\n") + assert.Equal(t, KernelLockdownIntegrity, KernelLockdownMode()) + + setIntegrity(t, path, "[none] integrity confidentiality\n") + assert.Equal(t, KernelLockdownNone, KernelLockdownMode()) + + setIntegrity(t, path, "none integrity [confidentiality]\n") + assert.Equal(t, KernelLockdownConfidentiality, KernelLockdownMode()) + + setIntegrity(t, path, "whatever\n") + assert.Equal(t, KernelLockdownOther, KernelLockdownMode()) + + setIntegrity(t, path, "") + assert.Equal(t, KernelLockdownIntegrity, KernelLockdownMode()) + + setIntegrity(t, path, "[none] integrity confidentiality\n") + setNotReadable(t, path) + assert.Equal(t, KernelLockdownIntegrity, KernelLockdownMode()) +}