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: map changes #3328

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bpf/lib/process.h
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ struct {

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 32768);
__uint(max_entries, 1);
__type(key, __u32);
__type(value, struct execve_map_value);
} execve_map SEC(".maps");
Expand Down
3 changes: 3 additions & 0 deletions docs/data/tetragon_flags.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pkg/option/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ type config struct {
EventCacheRetryDelay int

CompatibilitySyscall64SizeType bool

ExecveMapEntries string
}

var (
Expand Down
5 changes: 5 additions & 0 deletions pkg/option/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ const (
KeyEventCacheRetryDelay = "event-cache-retry-delay"

KeyCompatibilitySyscall64SizeType = "enable-compatibility-syscall64-size-type"

KeyExecveMapEntries = "execve-map-entries"
)

type UsernameMetadaCode int
Expand Down Expand Up @@ -252,6 +254,7 @@ func ReadAndSetFlags() error {

Config.CompatibilitySyscall64SizeType = viper.GetBool(KeyCompatibilitySyscall64SizeType)

Config.ExecveMapEntries = viper.GetString(KeyExecveMapEntries)
return nil
}

Expand Down Expand Up @@ -419,4 +422,6 @@ func AddFlags(flags *pflag.FlagSet) {
flags.Int(KeyEventCacheRetryDelay, defaults.DefaultEventCacheRetryDelay, "Delay in seconds between event cache retries")

flags.Bool(KeyCompatibilitySyscall64SizeType, false, "syscall64 type will produce output of type size (compatibility flag, will be removed in v1.4)")

flags.String(KeyExecveMapEntries, "32768", "Set entries for execve_map table (entries/size/max)")
}
62 changes: 59 additions & 3 deletions pkg/sensors/base/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,27 @@ package base

import (
"log"
"os"
"strconv"
"strings"
"sync"
"testing"
"unsafe"

"github.com/cilium/tetragon/pkg/errmetrics"
"github.com/cilium/tetragon/pkg/ksyms"
"github.com/cilium/tetragon/pkg/logger"
"github.com/cilium/tetragon/pkg/mbset"
"github.com/cilium/tetragon/pkg/option"
"github.com/cilium/tetragon/pkg/sensors"
"github.com/cilium/tetragon/pkg/sensors/exec/config"
"github.com/cilium/tetragon/pkg/sensors/exec/execvemap"
"github.com/cilium/tetragon/pkg/sensors/program"
"github.com/cilium/tetragon/pkg/strutils"
)

const (
ExecveMapMaxEntries = 32768
)

var (
Expand Down Expand Up @@ -55,7 +66,7 @@ var (
/* Event Ring map */
TCPMonMap = program.MapBuilder("tcpmon_map", Execve)
/* Networking and Process Monitoring maps */
ExecveMap = program.MapBuilder("execve_map", Execve)
ExecveMap = program.MapBuilder("execve_map", Execve, Exit, Fork, ExecveBprmCommit)
ExecveTailCallsMap = program.MapBuilderProgram("execve_calls", Execve)

ExecveJoinMap = program.MapBuilder("tg_execve_joined_info_map", ExecveBprmCommit)
Expand All @@ -73,7 +84,44 @@ var (
ErrMetricsMap = program.MapBuilder(errmetrics.MapName, Execve)
)

func setupPrograms() {
func readThreadsMax(path string) (int64, error) {
data, err := os.ReadFile(path)
if err != nil {
return 0, err
}
str := strings.TrimRight(string(data), "\n")
return strconv.ParseInt(str, 10, 32)
}

func GetExecveMapEntries(str string) int {
entry := int(unsafe.Sizeof(execvemap.ExecveValue{}))

if len(str) == 0 {
return ExecveMapMaxEntries
}
// pure number of entries
if val, err := strconv.ParseUint(str, 10, 32); err == nil {
return int(val)
Dismissed Show dismissed Hide dismissed
}
// follow threads-max entries
if str == "max" {
if val, err := readThreadsMax("/proc/sys/kernel/threads-max"); err == nil {
return int(val)
}
logger.GetLogger().Warn("Failed to read /proc/sys/kernel/threads-max file, falling back to default")
return ExecveMapMaxEntries
}
// set entries based on size
size, err := strutils.ParseSize(str)
if err != nil {
logger.GetLogger().Warn("Failed to parse --execve-map-max value, falling back to default")
return ExecveMapMaxEntries
}
val := size / entry
return val
}

func setupSensor() {
// exit program function
ks, err := ksyms.KernelSymbols()
if err == nil {
Expand All @@ -92,6 +140,14 @@ func setupPrograms() {
}
}
logger.GetLogger().Infof("Exit probe on %s", Exit.Attach)

entries := GetExecveMapEntries(option.Config.ExecveMapEntries)
ExecveMap.SetMaxEntries(entries)

logger.GetLogger().
WithField("size", strutils.SizeWithSuffix(entries*int(unsafe.Sizeof(execvemap.ExecveValue{})))).
WithField("config", option.Config.ExecveMapEntries).
Infof("Set execve_map entries %d", entries)
}

func GetExecveMap() *program.Map {
Expand Down Expand Up @@ -137,7 +193,7 @@ func initBaseSensor() *sensors.Sensor {
sensor := sensors.Sensor{
Name: basePolicy,
}
setupPrograms()
setupSensor()
sensor.Progs = GetDefaultPrograms()
sensor.Maps = GetDefaultMaps()
return ApplyExtensions(&sensor)
Expand Down
2 changes: 1 addition & 1 deletion pkg/sensors/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ func handleThrottleEvent(r *bytes.Reader) ([]observer.Event, error) {
type execProbe struct{}

func (e *execProbe) LoadProbe(args sensors.LoadProbeArgs) error {
return program.LoadTracepointProgram(args.BPFDir, args.Load, args.Verbose)
return program.LoadTracepointProgram(args.BPFDir, args.Load, args.Maps, args.Verbose)
}

func init() {
Expand Down
16 changes: 15 additions & 1 deletion pkg/sensors/exec/procevents/proc_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,13 +370,27 @@ func writeExecveMap(procs []procs) {
panic(err)
}
}

entries, ok := base.ExecveMap.GetMaxEntries()
if !ok {
logger.GetLogger().Warnf("Failed to get number of execve_map entries, using default.")
entries = base.ExecveMapMaxEntries
}
logger.GetLogger().Infof("Maximum execve_map entries %d, need to add %d.", entries, len(procs))
i := uint32(0)

inInitTree := make(map[uint32]struct{})
for _, p := range procs {
k, v := procToKeyValue(p, inInitTree)
err := m.Put(k, v)
if err != nil {
logger.GetLogger().WithField("value", v).WithError(err).Warn("failed to put value in execve_map")
}

i++
if i == entries {
break
}
}
// In order for kprobe events from kernel ctx to not abort we need the
// execve lookup to map to a valid entry. So to simplify the kernel side
Expand All @@ -393,7 +407,7 @@ func writeExecveMap(procs []procs) {
})
m.Close()

updateExecveMapStats(int64(len(procs)))
updateExecveMapStats(int64(entries))
}

func pushEvents(ps []procs) {
Expand Down
19 changes: 10 additions & 9 deletions pkg/sensors/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func (s *Sensor) Load(bpfDir string) (err error) {
continue
}

if err = observerLoadInstance(bpfDir, p); err != nil {
if err = observerLoadInstance(bpfDir, p, s.Maps); err != nil {
return err
}
p.LoadState.RefInc()
Expand Down Expand Up @@ -408,7 +408,7 @@ func mergeSensors(sensors []*Sensor) *Sensor {
}
}

func observerLoadInstance(bpfDir string, load *program.Program) error {
func observerLoadInstance(bpfDir string, load *program.Program, maps []*program.Map) error {
version, _, err := kernels.GetKernelVersion(option.Config.KernelVersion, option.Config.ProcFS)
if err != nil {
return err
Expand All @@ -420,33 +420,33 @@ func observerLoadInstance(bpfDir string, load *program.Program) error {
"kern_version": version,
}).Debugf("observerLoadInstance %s %d", load.Name, version)
if load.Type == "tracepoint" {
err = loadInstance(bpfDir, load, version, option.Config.Verbosity)
err = loadInstance(bpfDir, load, maps, version, option.Config.Verbosity)
if err != nil {
l.WithField(
"tracepoint", load.Name,
).Info("Failed to load, trying to remove and retrying")
load.Unload(true)
err = loadInstance(bpfDir, load, version, option.Config.Verbosity)
err = loadInstance(bpfDir, load, maps, version, option.Config.Verbosity)
}
if err != nil {
return fmt.Errorf("failed prog %s kern_version %d LoadTracingProgram: %w",
load.Name, version, err)
}
} else if load.Type == "raw_tracepoint" || load.Type == "raw_tp" {
err = loadInstance(bpfDir, load, version, option.Config.Verbosity)
err = loadInstance(bpfDir, load, maps, version, option.Config.Verbosity)
if err != nil {
l.WithField(
"raw_tracepoint", load.Name,
).Info("Failed to load, trying to remove and retrying")
load.Unload(true)
err = loadInstance(bpfDir, load, version, option.Config.Verbosity)
err = loadInstance(bpfDir, load, maps, version, option.Config.Verbosity)
}
if err != nil {
return fmt.Errorf("failed prog %s kern_version %d LoadRawTracepointProgram: %w",
load.Name, version, err)
}
} else {
err = loadInstance(bpfDir, load, version, option.Config.Verbosity)
err = loadInstance(bpfDir, load, maps, version, option.Config.Verbosity)
if err != nil && load.ErrorFatal {
return fmt.Errorf("failed prog %s kern_version %d loadInstance: %w",
load.Name, version, err)
Expand All @@ -455,15 +455,15 @@ func observerLoadInstance(bpfDir string, load *program.Program) error {
return nil
}

func loadInstance(bpfDir string, load *program.Program, version, verbose int) error {
func loadInstance(bpfDir string, load *program.Program, maps []*program.Map, version, verbose int) error {
// Check if the load.type is a standard program type. If so, use the standard loader.
loadFn, ok := standardTypes[load.Type]
if ok {
logger.GetLogger().WithField("Program", load.Name).
WithField("Type", load.Type).
WithField("Attach", load.Attach).
Debug("Loading BPF program")
return loadFn(bpfDir, load, verbose)
return loadFn(bpfDir, load, maps, verbose)
}
// Otherwise, check for a registered probe type. If one exists, use that.
probe, ok := registeredProbeLoad[load.Type]
Expand All @@ -479,6 +479,7 @@ func loadInstance(bpfDir string, load *program.Program, version, verbose int) er
Load: load,
Version: version,
Verbose: verbose,
Maps: maps,
})
}

Expand Down
8 changes: 4 additions & 4 deletions pkg/sensors/program/cgroup/cgroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,20 @@ var (

func LoadSockOpt(
bpfDir string,
load *program.Program, verbose int,
load *program.Program, maps []*program.Map, verbose int,
) error {
return LoadCgroupProgram(bpfDir, load, verbose)
return LoadCgroupProgram(bpfDir, load, maps, verbose)
}

func LoadCgroupProgram(
bpfDir string,
load *program.Program, verbose int) error {
load *program.Program, maps []*program.Map, verbose int) error {
if fgsCgroupFD < 0 {
fd, err := unix.Open(fgsCgroupPath, unix.O_RDONLY, 0)
if err != nil {
return fmt.Errorf("failed to open '%s': %w", fgsCgroupPath, err)
}
fgsCgroupFD = fd
}
return program.LoadProgram(bpfDir, load, program.RawAttach(fgsCgroupFD), verbose)
return program.LoadProgram(bpfDir, load, maps, program.RawAttach(fgsCgroupFD), verbose)
}
Loading
Loading