Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tetragon: Remove sensors on exit not programs #1514

Merged
merged 6 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 12 additions & 6 deletions cmd/tetragon/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,6 @@ func tetragonExecute() error {
obs := observer.NewObserver(option.Config.TracingPolicy)
defer func() {
obs.PrintStats()
obs.RemovePrograms()
}()

defaultLevel := logger.GetLogLevel()
Expand Down Expand Up @@ -277,6 +276,9 @@ func tetragonExecute() error {
if err := obs.InitSensorManager(sensorMgWait); err != nil {
return err
}
defer func() {
observer.RemoveSensors(ctx)
}()

/* Remove any stale programs, otherwise feature set change can cause
* old programs to linger resulting in undefined behavior. And because
Expand Down Expand Up @@ -338,7 +340,7 @@ func tetragonExecute() error {
pm, err := tetragonGrpc.NewProcessManager(
ctx,
&cleanupWg,
observer.SensorManager,
observer.GetSensorManager(),
hookRunner)
if err != nil {
return err
Expand All @@ -356,20 +358,24 @@ func tetragonExecute() error {
obs.AddListener(pm)
saveInitInfo()
if option.Config.EnableK8s {
go crd.WatchTracePolicy(ctx, observer.SensorManager)
go crd.WatchTracePolicy(ctx, observer.GetSensorManager())
}

obs.LogPinnedBpf(observerDir)

// load base sensor
if err := base.GetInitialSensor().Load(observerDir, observerDir); err != nil {
base := base.GetInitialSensor()
if err := base.Load(observerDir, observerDir); err != nil {
return err
}
defer func() {
base.Unload()
}()

// now that the base sensor was loaded, we can start the sensor manager
close(sensorMgWait)
sensorMgWait = nil
observer.SensorManager.LogSensorsAndProbes(ctx)
observer.GetSensorManager().LogSensorsAndProbes(ctx)

err = loadTpFromDir(ctx, option.Config.TracingPolicyDir)
if err != nil {
Expand Down Expand Up @@ -444,7 +450,7 @@ func addTracingPolicy(ctx context.Context, file string) error {
return err
}

err = observer.SensorManager.AddTracingPolicy(ctx, tp)
err = observer.GetSensorManager().AddTracingPolicy(ctx, tp)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/bench/bench.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func startBenchmarkExporter(ctx context.Context, obs *observer.Observer, summary
processManager, err := grpc.NewProcessManager(
ctx,
&wg,
observer.SensorManager,
observer.GetSensorManager(),
hookRunner)
if err != nil {
return err
Expand Down
17 changes: 11 additions & 6 deletions pkg/observer/observer.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@ var (
eventHandler = make(map[uint8]func(r *bytes.Reader) ([]Event, error))

observerList []*Observer

/* SensorManager handles dynamic sensors loading / unloading. */
SensorManager *sensors.Manager
)

type Event notify.Message
Expand Down Expand Up @@ -342,9 +339,11 @@ func (k *Observer) Start(ctx context.Context) error {

// InitSensorManager starts the sensor controller
func (k *Observer) InitSensorManager(waitChan chan struct{}) error {
var err error
SensorManager, err = sensors.StartSensorManager(option.Config.BpfDir, option.Config.MapDir, waitChan)
return err
mgr, err := sensors.StartSensorManager(option.Config.BpfDir, option.Config.MapDir, waitChan)
if err != nil {
return err
}
return SetSensorManager(mgr)
}

func NewObserver(configFile string) *Observer {
Expand Down Expand Up @@ -401,6 +400,12 @@ func (k *Observer) RemovePrograms() {
RemovePrograms(option.Config.BpfDir, option.Config.MapDir)
}

func RemoveSensors(ctx context.Context) {
if mgr := GetSensorManager(); mgr != nil {
mgr.RemoveAllSensors(ctx)
}
}

// Log Active pinned BPF resources
func (k *Observer) LogPinnedBpf(observerDir string) {
finfo, err := os.Stat(observerDir)
Expand Down
37 changes: 24 additions & 13 deletions pkg/observer/observertesthelper/observer_test_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ func testDone(tb testing.TB, obs *observer.Observer) {
}
}

obs.RemovePrograms()
obs.PrintStats()
obs.Remove()
}
Expand Down Expand Up @@ -213,8 +212,6 @@ func newDefaultObserver(oo *testObserverOptions) *observer.Observer {
}

func getDefaultObserver(tb testing.TB, ctx context.Context, base *sensors.Sensor, opts ...TestOption) (*observer.Observer, error) {
var cnfSensor *sensors.Sensor

testutils.CaptureLog(tb, logger.GetLogger().(*logrus.Logger))

o := newDefaultTestOptions(opts...)
Expand Down Expand Up @@ -245,15 +242,8 @@ func getDefaultObserver(tb testing.TB, ctx context.Context, base *sensors.Sensor
return nil, fmt.Errorf("failed to parse tracingpolicy: %w", err)
}
}
if tp != nil {
var err error
cnfSensor, err = sensors.GetMergedSensorFromParserPolicy(tp)
if err != nil {
return nil, err
}
}

if err := loadSensor(tb, base, cnfSensor); err != nil {
if err := loadObserver(tb, ctx, base, tp); err != nil {
return nil, err
}

Expand Down Expand Up @@ -379,9 +369,10 @@ func loadExporter(tb testing.TB, ctx context.Context, obs *observer.Observer, op

// NB(kkourt): we use the global that was set up by InitSensorManager(). We should clean
// this up and remove/hide the global variable.
sensorManager := observer.SensorManager
sensorManager := observer.GetSensorManager()
tb.Cleanup(func() {
sensorManager.StopSensorManager(context.TODO())
sensorManager.StopSensorManager(ctx)
observer.ResetSensorManager()
})

if oo.crd {
Expand Down Expand Up @@ -438,6 +429,26 @@ func loadExporter(tb testing.TB, ctx context.Context, obs *observer.Observer, op
return nil
}

func loadObserver(tb testing.TB, ctx context.Context, base *sensors.Sensor,
tp tracingpolicy.TracingPolicy) error {

if err := base.Load(option.Config.BpfDir, option.Config.MapDir); err != nil {
tb.Fatalf("Load base error: %s\n", err)
}

if tp != nil {
if err := observer.GetSensorManager().AddTracingPolicy(ctx, tp); err != nil {
tb.Fatalf("SensorManager.AddTracingPolicy error: %s\n", err)
}
}

tb.Cleanup(func() {
observer.RemoveSensors(ctx)
base.Unload()
})
return nil
}

func loadSensor(tb testing.TB, base *sensors.Sensor, sens *sensors.Sensor) error {
if err := base.Load(option.Config.BpfDir, option.Config.MapDir); err != nil {
tb.Fatalf("Load base error: %s\n", err)
Expand Down
40 changes: 40 additions & 0 deletions pkg/observer/sensor_manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Tetragon

package observer

import (
"fmt"
"sync"

"github.com/cilium/tetragon/pkg/sensors"
)

var (
// SensorManager handles dynamic sensors loading / unloading, and is a global variable for
// now
sensorManager *sensors.Manager
sensorManagerMu sync.Mutex
)

// ResetSensorManager resets the global sensorManager variable to nil. Intended only for testing.
func ResetSensorManager() {
sensorManager = nil
}

func SetSensorManager(sm *sensors.Manager) error {
sensorManagerMu.Lock()
defer sensorManagerMu.Unlock()

if sensorManager != nil {
return fmt.Errorf("observer sensorManager already set")
}
sensorManager = sm
return nil
}

func GetSensorManager() *sensors.Manager {
sensorManagerMu.Lock()
defer sensorManagerMu.Unlock()
return sensorManager
}
12 changes: 7 additions & 5 deletions pkg/sensors/base/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ var (
/* Internal statistics for debugging */
ExecveStats = program.MapBuilder("execve_map_stats", Execve)
ExecveJoinMapStats = program.MapBuilder("tg_execve_joined_info_map_stats", ExecveBprmCommit)

sensor = sensors.Sensor{
Name: "__base__",
Progs: GetDefaultPrograms(),
Maps: GetDefaultMaps(),
}
)

func GetExecveMap() *program.Map {
Expand Down Expand Up @@ -100,11 +106,7 @@ func GetDefaultMaps() []*program.Map {

// GetInitialSensor returns the base sensor
func GetInitialSensor() *sensors.Sensor {
return &sensors.Sensor{
Name: "__base__",
Progs: GetDefaultPrograms(),
Maps: GetDefaultMaps(),
}
return &sensor
}

// ExecObj returns the exec object based on the kernel version
Expand Down
4 changes: 1 addition & 3 deletions pkg/sensors/exec/cgroups_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -589,9 +589,7 @@ func setupTgRuntimeConf(t *testing.T, trackingCgrpLevel, logLevel, hierarchyId,
}

func setupObserver(ctx context.Context, t *testing.T) *tus.TestSensorManager {
testManager := tus.StartTestSensorManager(ctx, t)
observer.SensorManager = testManager.Manager

testManager := tus.GetTestSensorManager(ctx, t)
if err := observer.InitDataCache(1024); err != nil {
t.Fatalf("failed to call observer.InitDataCache %s", err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/sensors/exec/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ func TestLoadInitialSensor(t *testing.T) {

tus.CheckSensorLoad([]*sensors.Sensor{sensor}, sensorMaps, sensorProgs, t)

sensors.UnloadAll()
sensor.Unload()
}

func TestDocker(t *testing.T) {
Expand Down
19 changes: 19 additions & 0 deletions pkg/sensors/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package sensors

import (
"errors"
"fmt"

slimv1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/meta/v1"
Expand Down Expand Up @@ -191,7 +192,25 @@ func (h *handler) addSensor(op *sensorAdd) error {
return nil
}

func removeAllSensors(h *handler) error {
var errs error
for _, col := range h.collections {
if err := col.unload(); err != nil {
errs = errors.Join(errs, err)
}
delete(h.collections, col.name)
}
return errs
}

func (h *handler) removeSensor(op *sensorRemove) error {
if op.all {
if op.name != "" {
return fmt.Errorf("removeSensor called with all flag and sensor name %s",
op.name)
}
return removeAllSensors(h)
}
col, exists := h.collections[op.name]
if !exists {
return fmt.Errorf("sensor %s does not exist", op.name)
Expand Down
8 changes: 8 additions & 0 deletions pkg/sensors/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,3 +369,11 @@ func UnloadAll() {
AllPrograms = []*program.Program{}
AllMaps = []*program.Map{}
}

func UnloadSensors(sens []*Sensor) {
for i := range sens {
if err := sens[i].Unload(); err != nil {
logger.GetLogger().Warnf("Failed to unload sensor: %s", err)
}
}
}
15 changes: 15 additions & 0 deletions pkg/sensors/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,20 @@ func (h *Manager) RemoveSensor(ctx context.Context, sensorName string) error {
return err
}

func (h *Manager) RemoveAllSensors(ctx context.Context) error {
retc := make(chan error)
op := &sensorRemove{
ctx: ctx,
all: true,
retChan: retc,
}

h.sensorCtl <- op
err := <-retc

return err
}

func (h *Manager) StopSensorManager(ctx context.Context) error {
retc := make(chan error)
op := &sensorCtlStop{
Expand Down Expand Up @@ -325,6 +339,7 @@ type sensorAdd struct {
type sensorRemove struct {
ctx context.Context
name string
all bool
retChan chan error
}

Expand Down
4 changes: 1 addition & 3 deletions pkg/sensors/test/lseek_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

ec "github.com/cilium/tetragon/api/v1/tetragon/codegen/eventchecker"
"github.com/cilium/tetragon/pkg/jsonchecker"
"github.com/cilium/tetragon/pkg/observer"
"github.com/cilium/tetragon/pkg/observer/observertesthelper"
_ "github.com/cilium/tetragon/pkg/sensors/exec"
tus "github.com/cilium/tetragon/pkg/testutils/sensors"
Expand Down Expand Up @@ -77,8 +76,7 @@ func TestSensorLseekEnable(t *testing.T) {

sensor := GetTestSensor()

smanager := tus.StartTestSensorManager(ctx, t)
observer.SensorManager = smanager.Manager
smanager := tus.GetTestSensorManager(ctx, t)
smanager.AddAndEnableSensor(ctx, t, sensor, sensor.Name)

observertesthelper.LoopEvents(ctx, t, &doneWG, &readyWG, obs)
Expand Down
12 changes: 6 additions & 6 deletions pkg/sensors/tracing/kprobe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3616,10 +3616,6 @@ spec:
- call: "sys_write"
syscall: true
`
b := base.GetInitialSensor()
if err := b.Load(option.Config.BpfDir, option.Config.MapDir); err != nil {
return fmt.Errorf("load base sensor failed: %w", err)
}

tp, _ := tracingpolicy.FromYAML(testHook)
if tp == nil {
Expand All @@ -3630,7 +3626,11 @@ spec:
if err != nil {
return err
}
return sens.Load(option.Config.BpfDir, option.Config.MapDir)
err = sens.Load(option.Config.BpfDir, option.Config.MapDir)
if err != nil {
return err
}
return sens.Unload()
}

func TestKprobeBpfAttr(t *testing.T) {
Expand Down Expand Up @@ -3777,7 +3777,7 @@ spec:

tus.CheckSensorLoad(sens, sensorMaps, sensorProgs, t)

sensors.UnloadAll()
sensors.UnloadSensors(sens)
}

func TestFakeSyscallError(t *testing.T) {
Expand Down