Skip to content

Commit

Permalink
feat(ksymbols): reimplement ksymbols
Browse files Browse the repository at this point in the history
This implementation stores all symbols, or if a `requiredDataSymbolsOnly`
flag is used when creating the symbol table, only non-data symbols are saved
(and required data symbols must be registered before updating).
This new implementation uses a generic symbol table implementation that is
responsible for managing symbol lookups, and can be used by future code for
managing exeutable file symbols.
  • Loading branch information
oshaked1 committed Jan 15, 2025
1 parent 0495d22 commit 56abaac
Show file tree
Hide file tree
Showing 13 changed files with 898 additions and 387 deletions.
2 changes: 1 addition & 1 deletion pkg/ebpf/event_parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func registerSyscallChecker(t *Tracee, eventParams []map[string]filters.Filter[*
if err := probeGroup.AddProbe(handle, probe); err != nil {
return errfmt.WrapError(err)
}
if err := probeGroup.Attach(handle, t.kernelSymbols); err != nil {
if err := probeGroup.Attach(handle, t.getKernelSymbols()); err != nil {
// Report attachment errors but don't fail, because it may be a syscall that doesn't exist on this system
logger.Warnw("Failed to attach syscall checker kprobe", "syscall", syscall.name, "error", err)
continue
Expand Down
6 changes: 3 additions & 3 deletions pkg/ebpf/hooked_syscall_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,11 @@ func (t *Tracee) getSyscallNameByKerVer(restrictions []events.KernelRestrictions
// populateExpectedSyscallTableArray fills the expected values of the syscall table
func (t *Tracee) populateExpectedSyscallTableArray(tableMap *bpf.BPFMap) error {
// Get address to the function that defines the not implemented sys call
niSyscallSymbol, err := t.kernelSymbols.GetSymbolByOwnerAndName("system", events.SyscallPrefix+"ni_syscall")
niSyscallSymbol, err := t.getKernelSymbols().GetSymbolByOwnerAndName("system", events.SyscallPrefix+"ni_syscall")
if err != nil {
e := err
// RHEL 8.x uses sys_ni_syscall instead of __arch_ni_syscall
niSyscallSymbol, err = t.kernelSymbols.GetSymbolByOwnerAndName("system", "sys_ni_syscall")
niSyscallSymbol, err = t.getKernelSymbols().GetSymbolByOwnerAndName("system", "sys_ni_syscall")
if err != nil {
logger.Debugw("hooked_syscall: syscall symbol not found", "name", "sys_ni_syscall")
return e
Expand All @@ -188,7 +188,7 @@ func (t *Tracee) populateExpectedSyscallTableArray(tableMap *bpf.BPFMap) error {
continue
}

kernelSymbol, err := t.kernelSymbols.GetSymbolByOwnerAndName("system", events.SyscallPrefix+syscallName)
kernelSymbol, err := t.getKernelSymbols().GetSymbolByOwnerAndName("system", events.SyscallPrefix+syscallName)
if err != nil {
logger.Warnw(fmt.Sprintf("hooked_syscall: Unable to locate syscall symbol... permanently skipping hook check for syscall ID %d", index))
zero := 0
Expand Down
2 changes: 1 addition & 1 deletion pkg/ebpf/ksymbols.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (t *Tracee) UpdateKallsyms() error {
// For every ksymbol required by tracee ...
for _, required := range allReqSymbols {
// ... get the symbol address from the kallsyms file ...
symbol, err := t.kernelSymbols.GetSymbolByOwnerAndName(globalSymbolOwner, required)
symbol, err := t.getKernelSymbols().GetSymbolByOwnerAndName(globalSymbolOwner, required)
if err != nil {
logger.Debugw("failed to get symbol", "symbol", required, "error", err)
continue
Expand Down
2 changes: 1 addition & 1 deletion pkg/ebpf/probes/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func (p *TraceProbe) attach(module *bpf.Module, args ...interface{}) error {
var err error
var link *bpf.BPFLink
var attachFunc func(uint64) (*bpf.BPFLink, error)
var syms []environment.KernelSymbol
var syms []*environment.KernelSymbol
// https://github.com/aquasecurity/tracee/issues/3653#issuecomment-1832642225
//
// After commit b022f0c7e404 ('tracing/kprobes: Return EADDRNOTAVAIL
Expand Down
8 changes: 5 additions & 3 deletions pkg/ebpf/processor_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/aquasecurity/tracee/pkg/logger"
"github.com/aquasecurity/tracee/pkg/time"
"github.com/aquasecurity/tracee/pkg/utils"
"github.com/aquasecurity/tracee/pkg/utils/environment"
"github.com/aquasecurity/tracee/types/trace"
)

Expand Down Expand Up @@ -233,10 +234,11 @@ func (t *Tracee) processDoInitModule(event *trace.Event) error {

err := capabilities.GetInstance().EBPF(
func() error {
err := t.kernelSymbols.Refresh()
newKernelSymbols, err := environment.NewKernelSymbolTable(true, true, t.requiredKsyms...)
if err != nil {
return errfmt.WrapError(err)
}
t.setKernelSymbols(newKernelSymbols)
return t.UpdateKallsyms()
},
)
Expand Down Expand Up @@ -281,7 +283,7 @@ func (t *Tracee) processHookedProcFops(event *trace.Event) error {
if addr == 0 { // address is in text segment, marked as 0
continue
}
hookingFunction := utils.ParseSymbol(addr, t.kernelSymbols)
hookingFunction := t.getKernelSymbols().GetPotentiallyHiddenSymbolByAddr(addr)[0]
if hookingFunction.Owner == "system" {
continue
}
Expand Down Expand Up @@ -326,7 +328,7 @@ func (t *Tracee) processPrintMemDump(event *trace.Event) error {
}

addressUint64 := uint64(address)
symbol := utils.ParseSymbol(addressUint64, t.kernelSymbols)
symbol := t.getKernelSymbols().GetPotentiallyHiddenSymbolByAddr(addressUint64)[0]
var utsName unix.Utsname
arch := ""
if err := unix.Uname(&utsName); err != nil {
Expand Down
53 changes: 29 additions & 24 deletions pkg/ebpf/tracee.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,8 @@ type Tracee struct {
writtenFiles map[string]string
netCapturePcap *pcaps.Pcaps
// Internal Data
readFiles map[string]string
pidsInMntns bucketscache.BucketsCache // first n PIDs in each mountns
kernelSymbols *environment.KernelSymbolTable
readFiles map[string]string
pidsInMntns bucketscache.BucketsCache // first n PIDs in each mountns
// eBPF
bpfModule *bpf.Module
defaultProbes *probes.ProbeGroup
Expand Down Expand Up @@ -123,6 +122,9 @@ type Tracee struct {
policyManager *policy.Manager
// The dependencies of events used by Tracee
eventsDependencies *dependencies.Manager
// A reference to a environment.KernelSymbolTable that might change at runtime.
// This should only be accessed using t.getKernelSymbols() and t.setKernelSymbols()
kernelSymbols unsafe.Pointer
// Ksymbols needed to be kept alive in table.
// This does not mean they are required for tracee to function.
// TODO: remove this in favor of dependency manager nodes
Expand All @@ -137,6 +139,14 @@ func (t *Tracee) Engine() *engine.Engine {
return t.sigEngine
}

func (t *Tracee) getKernelSymbols() *environment.KernelSymbolTable {
return (*environment.KernelSymbolTable)(atomic.LoadPointer(&t.kernelSymbols))
}

func (t *Tracee) setKernelSymbols(kernelSymbols *environment.KernelSymbolTable) {
atomic.StorePointer(&t.kernelSymbols, unsafe.Pointer(kernelSymbols))
}

// New creates a new Tracee instance based on a given valid Config. It is expected that it won't
// cause external system side effects (reads, writes, etc).
func New(cfg config.Config) (*Tracee, error) {
Expand Down Expand Up @@ -362,12 +372,13 @@ func (t *Tracee) Init(ctx gocontext.Context) error {

err = capabilities.GetInstance().Specific(
func() error {
t.kernelSymbols, err = environment.NewKernelSymbolTable(
environment.WithRequiredSymbols(t.requiredKsyms),
)
// Cleanup memory in list
t.requiredKsyms = []string{}
return err
// t.requiredKsyms may contain non-data symbols, but it doesn't affect the validity of this call
kernelSymbols, err := environment.NewKernelSymbolTable(true, true, t.requiredKsyms...)
if err != nil {
return err
}
t.setKernelSymbols(kernelSymbols)
return nil
},
cap.SYSLOG,
)
Expand Down Expand Up @@ -604,13 +615,13 @@ func (t *Tracee) initDerivationTable() error {
events.SyscallTableCheck: {
events.HookedSyscall: {
Enabled: shouldSubmit(events.SyscallTableCheck),
DeriveFunction: derive.DetectHookedSyscall(t.kernelSymbols),
DeriveFunction: derive.DetectHookedSyscall(t.getKernelSymbols()),
},
},
events.PrintNetSeqOps: {
events.HookedSeqOps: {
Enabled: shouldSubmit(events.HookedSeqOps),
DeriveFunction: derive.HookedSeqOps(t.kernelSymbols),
DeriveFunction: derive.HookedSeqOps(t.getKernelSymbols()),
},
},
events.HiddenKernelModuleSeeker: {
Expand Down Expand Up @@ -913,18 +924,12 @@ func getUnavailbaleKsymbols(ksymbols []events.KSymbol, kernelSymbols *environmen
var unavailableSymbols []events.KSymbol

for _, ksymbol := range ksymbols {
sym, err := kernelSymbols.GetSymbolByName(ksymbol.GetSymbolName())
_, err := kernelSymbols.GetSymbolByName(ksymbol.GetSymbolName())
if err != nil {
// If the symbol is not found, it means it's unavailable.
unavailableSymbols = append(unavailableSymbols, ksymbol)
continue
}
for _, s := range sym {
if s.Address == 0 {
// Same if the symbol is found but its address is 0.
unavailableSymbols = append(unavailableSymbols, ksymbol)
}
}
}
return unavailableSymbols
}
Expand All @@ -944,7 +949,7 @@ func (t *Tracee) validateKallsymsDependencies() {
}

validateEvent := func(eventId events.ID) bool {
missingDepSyms := getUnavailbaleKsymbols(evtDefSymDeps(eventId), t.kernelSymbols)
missingDepSyms := getUnavailbaleKsymbols(evtDefSymDeps(eventId), t.getKernelSymbols())
shouldFailEvent := false
for _, symDep := range missingDepSyms {
if symDep.IsRequired() {
Expand Down Expand Up @@ -1159,7 +1164,7 @@ func (t *Tracee) attachEvent(id events.ID) error {
return err
}
for _, probe := range depsNode.GetDependencies().GetProbes() {
err := t.defaultProbes.Attach(probe.GetHandle(), t.cgroups, t.kernelSymbols)
err := t.defaultProbes.Attach(probe.GetHandle(), t.cgroups, t.getKernelSymbols())
if err == nil {
continue
}
Expand Down Expand Up @@ -1192,7 +1197,7 @@ func (t *Tracee) attachProbes() error {
logger.Errorw("Got node from type not requested")
return nil
}
err := t.defaultProbes.Attach(probeNode.GetHandle(), t.cgroups, t.kernelSymbols)
err := t.defaultProbes.Attach(probeNode.GetHandle(), t.cgroups, t.getKernelSymbols())
if err != nil {
return []dependencies.Action{dependencies.NewCancelNodeAddAction(err)}
}
Expand Down Expand Up @@ -1722,7 +1727,7 @@ func (t *Tracee) triggerSeqOpsIntegrityCheck(event trace.Event) {
}
var seqOpsPointers [len(derive.NetSeqOps)]uint64
for i, seqName := range derive.NetSeqOps {
seqOpsStruct, err := t.kernelSymbols.GetSymbolByOwnerAndName("system", seqName)
seqOpsStruct, err := t.getKernelSymbols().GetSymbolByOwnerAndName("system", seqName)
if err != nil {
continue
}
Expand Down Expand Up @@ -1816,7 +1821,7 @@ func (t *Tracee) triggerMemDump(event trace.Event) []error {

continue
}
symbol, err := t.kernelSymbols.GetSymbolByOwnerAndName(owner, name)
symbol, err := t.getKernelSymbols().GetSymbolByOwnerAndName(owner, name)
if err != nil {
if owner != "system" {
errs = append(errs, errfmt.Errorf("policy %d: invalid symbols provided to print_mem_dump event: %s - %v", p.ID, field, err))
Expand All @@ -1828,7 +1833,7 @@ func (t *Tracee) triggerMemDump(event trace.Event) []error {
prefixes := []string{"sys_", "__x64_sys_", "__arm64_sys_"}
var errSyscall error
for _, prefix := range prefixes {
symbol, errSyscall = t.kernelSymbols.GetSymbolByOwnerAndName(owner, prefix+name)
symbol, errSyscall = t.getKernelSymbols().GetSymbolByOwnerAndName(owner, prefix+name)
if errSyscall == nil {
err = nil
break
Expand Down
3 changes: 1 addition & 2 deletions pkg/events/derive/hooked_seq_ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"github.com/aquasecurity/tracee/pkg/errfmt"
"github.com/aquasecurity/tracee/pkg/events"
"github.com/aquasecurity/tracee/pkg/events/parse"
"github.com/aquasecurity/tracee/pkg/utils"
"github.com/aquasecurity/tracee/pkg/utils/environment"
"github.com/aquasecurity/tracee/types/trace"
)
Expand Down Expand Up @@ -43,7 +42,7 @@ func deriveHookedSeqOpsArgs(kernelSymbols *environment.KernelSymbolTable) derive
if addr == 0 {
continue
}
hookingFunction := utils.ParseSymbol(addr, kernelSymbols)
hookingFunction := kernelSymbols.GetPotentiallyHiddenSymbolByAddr(addr)[0]
seqOpsStruct := NetSeqOps[i/4]
seqOpsFunc := NetSeqOpsFuncs[i%4]
hookedSeqOps[seqOpsStruct+"_"+seqOpsFunc] =
Expand Down
Loading

0 comments on commit 56abaac

Please sign in to comment.