8000 adjust recently merged symbols_collision event and better document it by rafaeldtinoco · Pull Request #2743 · aquasecurity/tracee · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

adjust recently merged symbols_collision event and better document it #2743

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

Merged
merged 5 commits into from
Feb 20, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pkg/cmd/flags/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Events that match all trace expressions within a single scope will be traced.
To find out which scopes an event is related to, read the bitmask in one of these ways:

- using '-o format:json', matchedScopes JSON field (in decimal)
- using '-o format:table-verbose', SCOPES collumn (in hexadecimal)
- using '-o format:table-verbose', SCOPES column (in hexadecimal)

Examples:

Expand Down Expand Up @@ -212,7 +212,7 @@ func parseFilterFlag(flag string) (*filterFlag, error) {

func PrepareFilterScopes(filtersArr []string) (*filterscope.FilterScopes, error) {
eventsNameToID := events.Definitions.NamesToIDs()
// remove internal events since they shouldn't be accesible by users
// remove internal events since they shouldn't be accessible by users
for event, id := range eventsNameToID {
if events.Definitions.Get(id).Internal {
delete(eventsNameToID, event)
Expand Down
29 changes: 16 additions & 13 deletions pkg/containers/path_resolver.go
10000
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,33 @@ import (
"github.com/aquasecurity/tracee/pkg/capabilities"
)

// PathResolver generates an accessible absolute path from the root mount namespace to a relative
// path in a container. **NOTE**: to resolve host mount namespace, tracee reads from /proc/1/ns,
// requiring CAP_SYS_PTRACE capability.
type PathResolver struct {
// ContainerPathResolver generates an accessible absolute path from the root mount namespace to a
// relative path in a container. **NOTE**: to resolve host mount namespace, tracee reads from
// /proc/1/ns, requiring CAP_SYS_PTRACE capability.
type ContainerPathResolver struct {
fs fs.FS
mountNSPIDsCache *bucketscache.BucketsCache
}

// InitPathResolver create a resolver for paths from within containers.
func InitPathResolver(mountNSPIDsCache *bucketscache.BucketsCache) PathResolver {
return PathResolver{
// InitContainerPathResolver creates a resolver for paths from within containers.
func InitContainerPathResolver(mountNSPIDsCache *bucketscache.BucketsCache) *ContainerPathResolver {
return &ContainerPathResolver{
fs: os.DirFS("/"),
mountNSPIDsCache: mountNSPIDsCache,
}
}

// ResolveAbsolutePath resolves an absolute path, which might be inside a container, to an absolute path
// within the host mount namespace.
func (cPathRes PathResolver) ResolveAbsolutePath(mountNSAbsolutePath string, mountNS int) (string, error) {
// path should be absolute, except for e.g memfd_create files
// GetHostAbsPath translates an absolute path, which might be inside a container, to the
// correspondent abs path in the host mount namespace.
func (cPathRes *ContainerPathResolver) GetHostAbsPath(mountNSAbsolutePath string, mountNS int) (
string, error,
) {
// path should be absolute, except, for example, memfd_create files
if mountNSAbsolutePath == "" || mountNSAbsolutePath[0] != '/' {
return "", fmt.Errorf("file path is not absolute in its container mount point")
}
// try to access the root fs via another process in the same mount namespace (since the current process might have already died)
// try to access the root fs via another process in the same mount namespace
// (since the current process might have already died)
pids := cPathRes.mountNSPIDsCache.GetBucket(uint32(mountNS))
for _, pid := range pids {
procRootPath := fmt.Sprintf("/proc/%d/root", int(pid))
Expand All @@ -52,5 +55,5 @@ func (cPathRes PathResolver) ResolveAbsolutePath(mountNSAbsolutePath string, mou
return fmt.Sprintf("%s%s", procRootPath, mountNSAbsolutePath), nil
}
}
return "", fmt.Errorf("has no access to container fs - no recorded living process of mount namespace %d", mountNS)
return "", fmt.Errorf("has no access to container fs - no living task of mountns %d", mountNS)
}
8 changes: 4 additions & 4 deletions pkg/containers/path_resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ func TestPathResolver_ResolveAbsolutePath(t *testing.T) {
}
}

pres := InitPathResolver(&bucket)
pres := InitContainerPathResolver(&bucket)
pres.fs = mfs
_, err := pres.ResolveAbsolutePath(testFilePath, testMntNS)
_, err := pres.GetHostAbsPath(testFilePath, testMntNS)
if testCase.ExpectedError {
assert.Error(t, err)
} else {
Expand Down Expand Up @@ -137,9 +137,9 @@ func TestPathResolver_ResolveAbsolutePath(t *testing.T) {
mfs[fmt.Sprintf("proc/%d/root/%s", testPID, testCase.path)] = &fstest.MapFile{}
}

pres := InitPathResolver(&bucket)
pres := InitContainerPathResolver(&bucket)
pres.fs = mfs
_, err := pres.ResolveAbsolutePath(testCase.path, testMntNS)
_, err := pres.GetHostAbsPath(testCase.path, testMntNS)
if testCase.expectedError {
assert.Error(t, err)
} else {
Expand Down
195 changes: 83 additions & 112 deletions pkg/ebpf/tracee.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import (
"github.com/aquasecurity/tracee/types/trace"

lru "github.com/hashicorp/golang-lru"
"golang.org/x/exp/maps"
"golang.org/x/sys/unix"
"kernel.org/pub/linux/libs/security/libcap/cap"
)
Expand Down Expand Up @@ -156,41 +155,53 @@ type eventConfig struct {

// Tracee traces system calls and system events using eBPF
type Tracee struct {
config Config
probes probes.Probes
events map[events.ID]eventConfig
bpfModule *bpf.Module
eventsPerfMap *bpf.PerfBuffer
fileWrPerfMap *bpf.PerfBuffer
netCapPerfMap *bpf.PerfBuffer
bpfLogsPerfMap *bpf.PerfBuffer
eventsChannel chan []byte
fileWrChannel chan []byte
netCapChannel chan []byte
bpfLogsChannel chan []byte
lostEvChannel chan uint64
lostWrChannel chan uint64
lostNetCapChannel chan uint64
lostBPFLogChannel chan uint64
bootTime uint64
startTime uint64
stats metrics.Stats
capturedFiles map[string]int64
fileHashes *lru.Cache
writtenFiles map[string]string
pidsInMntns bucketscache.BucketsCache //record the first n PIDs (host) in each mount namespace, for internal usage
config Config
bootTime uint64
startTime uint64
running bool
outDir *os.File // use utils.XXX functions to access this file
stats metrics.Stats
// Events
events map[events.ID]eventConfig
eventsSorter *sorting.EventsChronologicalSorter
eventProcessor map[events.ID][]func(evt *trace.Event) error
eventDerivations derive.Table
// Artifacts
fileHashes *lru.Cache
capturedFiles map[string]int64
writtenFiles map[string]string
netCapturePcap *pcaps.Pcaps
// Internal Data
pidsInMntns bucketscache.BucketsCache // first n PIDs in each mountns
kernelSymbols helpers.KernelSymbolTable
// eBPF
bpfModule *bpf.Module
probes probes.Probes
// BPF Maps
StackAddressesMap *bpf.BPFMap
FDArgPathMap *bpf.BPFMap
netCapturePcap *pcaps.Pcaps
containers *containers.Containers
eventsSorter *sorting.EventsChronologicalSorter
eventProcessor map[events.ID][]func(evt *trace.Event) error
eventDerivations derive.Table
kernelSymbols helpers.KernelSymbolTable
triggerContexts trigger.Context
running bool
outDir *os.File // All file operations to output dir should be through the utils package file operations (like utils.OpenAt) using this directory file.
// Perf Buffers
eventsPerfMap *bpf.PerfBuffer // perf buffer for events
fileWrPerfMap *bpf.PerfBuffer // perf buffer for file writes
netCapPerfMap *bpf.PerfBuffer // perf buffer for network captures
bpfLogsPerfMap *bpf.PerfBuffer // perf buffer for bpf logs
// Events Channels
eventsChannel chan []byte // channel for events
fileWrChannel chan []byte // channel for file writes
netCapChannel chan []byte // channel for network captures
bpfLogsChannel chan []byte // channel for bpf logs
// Lost Events Channels
lostEvChannel chan uint64 // channel for lost events
lostWrChannel chan uint64 // channel for lost file writes
lostNetCapChannel chan uint64 // channel for lost network captures
lostBPFLogChannel chan uint64 // channel for lost bpf logs
// Containers
cgroups *cgroup.Cgroups
containers *containers.Containers
contPathResolver *containers.ContainerPathResolver
contSymbolsLoader *sharedobjs.ContainersSymbolsLoader
// Specific Events Needs
triggerContexts trigger.Context
}

func (t *Tracee) Stats() *metrics.Stats {
Expand Down Expand Up @@ -370,8 +381,30 @@ func (t *Tracee) Init() error {
}
}

// Canceling events missing kernel symbols
t.validateKallsymsDependencies()
t.validateKallsymsDependencies() // Canceling events missing kernel symbols

// Initialize buckets cache

if t.config.maxPidsCache == 0 {
t.config.maxPidsCache = 5 // default value for config.maxPidsCache
}
t.pidsInMntns.Init(t.config.maxPidsCache)

var mntNSProcs map[int]int
err = capabilities.GetInstance().Requested(func() error {
mntNSProcs, err = proc.GetMountNSFirstProcesses()
return err
},
cap.DAC_READ_SEARCH,
cap.SYS_PTRACE,
)
if err == nil {
for mountNS, pid := range mntNSProcs {
t.pidsInMntns.AddBucketItem(uint32(mountNS), uint32(pid))
}
} else {
logger.Debug("caps Requested", "error", err)
}

// Initialize cgroups filesystems

Expand All @@ -395,6 +428,9 @@ func (t *Tracee) Init() error {
return fmt.Errorf("error initializing containers: %w", err)
}

t.contPathResolver = containers.InitContainerPathResolver(&t.pidsInMntns)
t.contSymbolsLoader = sharedobjs.InitContainersSymbolsLoader(t.contPathResolver, 1024)

// Initialize event derivation logic

err = t.initDerivationTable()
Expand All @@ -418,28 +454,6 @@ func (t *Tracee) Init() error {
return err
}

// Initialize buckets cache
if t.config.maxPidsCache == 0 {
t.config.maxPidsCache = 5 // default value for config.maxPidsCache
}
t.pidsInMntns.Init(t.config.maxPidsCache)

var mntNSProcs map[int]int
err = capabilities.GetInstance().Requested(func() error {
mntNSProcs, err = proc.GetMountNSFirstProcesses()
return err
},
cap.DAC_READ_SEARCH,
cap.SYS_PTRACE,
)
if err == nil {
for mountNS, pid := range mntNSProcs {
t.pidsInMntns.AddBucketItem(uint32(mountNS), uint32(pid))
}
} else {
logger.Debug("caps Requested", "error", err)
}

// Initialize capture directory

if err := os.MkdirAll(t.config.Capture.OutputPath, 0755); err != nil {
Expand Down Expand Up @@ -564,54 +578,6 @@ func (t *Tracee) initTailCall(mapName string, mapIndexes []uint32, progName stri
// we declare for each Event (represented through it's ID) to which other
// events it can be derived and the corresponding function to derive into that Event.
func (t *Tracee) initDerivationTable() error {
// sanity check for containers dependency
if t.containers == nil {
return fmt.Errorf("nil tracee containers")
}

pathResolver := containers.InitPathResolver(&t.pidsInMntns)
soLoader := sharedobjs.InitContainersSymbolsLoader(&pathResolver, 1024)

symbolsLoadedFilters := map[string]filters.Filter{}

for filterScope := range t.config.FilterScopes.Map() {
maps.Copy(symbolsLoadedFilters, filterScope.ArgFilter.GetEventFilters(events.SymbolsLoaded))
}

loadWatchedSymbols := []string{}
loadWhitelistedLibs := []string{}

if len(symbolsLoadedFilters) > 0 {
watchedSymbolsFilter, ok := symbolsLoadedFilters["symbols"].(*filters.StringFilter)
if watchedSymbolsFilter != nil && ok {
loadWatchedSymbols = watchedSymbolsFilter.Equal()
}
whitelistedLibsFilter, ok := symbolsLoadedFilters["library_path"].(*filters.StringFilter)
if whitelistedLibsFilter != nil && ok {
loadWhitelistedLibs = whitelistedLibsFilter.NotEqual()
}
}

symbolsCollisionFilters := map[string]filters.Filter{}

for filterScope := range t.config.FilterScopes.Map() {
maps.Copy(symbolsCollisionFilters, filterScope.ArgFilter.GetEventFilters(events.SymbolsCollision))
}

collisionAllowListSymbols := []string{}
collisionDenyListSymbols := []string{}

collisionSymbolsFilter, ok := symbolsCollisionFilters["symbols"].(*filters.StringFilter)
if collisionSymbolsFilter != nil && ok {
collisionAllowListSymbols = collisionSymbolsFilter.Equal()
collisionDenyListSymbols = collisionSymbolsFilter.NotEqual()
}

soSymbolsCollisionsDeriveFn := derive.SymbolsCollision(
soLoader,
collisionAllowListSymbols,
collisionDenyListSymbols,
)

t.eventDerivations = derive.Table{
events.CgroupMkdir: {
Expand Down Expand Up @@ -642,20 +608,25 @@ func (t *Tracee) initDerivationTable() error {
events.SymbolsLoaded: {
Enabled: func() bool { return t.events[events.SymbolsLoaded].submit > 0 },
DeriveFunction: derive.SymbolsLoaded(
soLoader,
loadWatchedSymbols,
loadWhitelistedLibs,
t.contSymbolsLoader,
t.config.FilterScopes,
),
},
events.SymbolsCollision: {
Enabled: func() bool { return t.events[events.SymbolsCollision].submit > 0 },
DeriveFunction: soSymbolsCollisionsDeriveFn,
Enabled: func() bool { return t.events[events.SymbolsCollision].submit > 0 },
DeriveFunction: derive.SymbolsCollision(
t.contSymbolsLoader,
t.config.FilterScopes,
),
},
},
events.SchedProcessExec: {
events.SymbolsCollision: {
Enabled: func() bool { return t.events[events.SymbolsCollision].submit > 0 },
DeriveFunction: soSymbolsCollisionsDeriveFn,
Enabled: func() bool { return t.events[events.SymbolsCollision].submit > 0 },
DeriveFunction: derive.SymbolsCollision(
t.contSymbolsLoader,
t.config.FilterScopes,
),
},
},
//
Expand Down
Loading
0