Skip to content

Commit

Permalink
Bugfix: 32-bit compat program false positive
Browse files Browse the repository at this point in the history
32-bit programs on x86-64 may use a fast syscall method, whose code resides in the VDSO VMA.
This VMA is not  file backed, so it was incorrectly detected as anonymous memory.
  • Loading branch information
oshaked1 committed Jun 25, 2024
1 parent 49638e5 commit abd31e6
Show file tree
Hide file tree
Showing 9 changed files with 43 additions and 10 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/IBM/fluent-forward-go v0.2.2
github.com/Masterminds/sprig/v3 v3.2.3
github.com/aquasecurity/libbpfgo v0.7.0-libbpf-1.4
github.com/aquasecurity/libbpfgo/helpers v0.4.5
github.com/aquasecurity/tracee/api v0.0.0-20240613134034-89d2d4fc7689
github.com/aquasecurity/tracee/signatures/helpers v0.0.0-20240607205742-90c301111aee
github.com/aquasecurity/tracee/types v0.0.0-20240607205742-90c301111aee
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,8 @@ github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVb
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/aquasecurity/libbpfgo v0.7.0-libbpf-1.4 h1:rQ94U12Xlz2tncE8Rxnw3vpp/9hgUIEu3/Lv0/XQM0Q=
github.com/aquasecurity/libbpfgo v0.7.0-libbpf-1.4/go.mod h1:iI7QCIZ3kXG0MR+FHsDZck6cYs1y1HyZP3sMObBg0sk=
github.com/aquasecurity/libbpfgo/helpers v0.4.5 h1:eCoLclL3yqv4N9jqGL3T/ckrLPms2r13C4V2xtU75yc=
github.com/aquasecurity/libbpfgo/helpers v0.4.5/go.mod h1:j/TQLmsZpOIdF3CnJODzYngG4yu1YoDCoRMELxkQSSA=
github.com/aquasecurity/tracee/api v0.0.0-20240613134034-89d2d4fc7689 h1:mAOehSHrqAZ4lvn3AYgDxn+aDTKrv81ghNnGlteDB00=
github.com/aquasecurity/tracee/api v0.0.0-20240613134034-89d2d4fc7689/go.mod h1:km0QNkaoOVxU/IYF/Pw/ju/2SO1mYn+HJOIyMDtnfkE=
github.com/aquasecurity/tracee/signatures/helpers v0.0.0-20240607205742-90c301111aee h1:1KJy6Z2bSpmKQVPShU7hhbXgGVOgMwvzf9rjoWMTYEg=
Expand Down
2 changes: 1 addition & 1 deletion pkg/ebpf/c/common/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ static __inline int has_prefix(char *prefix, char *str, int n)
}

// prefix is too long
return 0;
return 1;
}

#endif
Expand Down
15 changes: 15 additions & 0 deletions pkg/ebpf/c/common/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ statfunc unsigned long get_vma_start(struct vm_area_struct *);
statfunc struct vm_area_struct *find_vma(struct task_struct *task, u64 addr);
statfunc bool vma_is_stack(struct vm_area_struct *vma);
statfunc bool vma_is_heap(struct vm_area_struct *vma);
statfunc bool vma_is_anon(struct vm_area_struct *vma);
statfunc bool vma_is_vdso(struct vm_area_struct *vma);

// FUNCTIONS

Expand Down Expand Up @@ -156,4 +158,17 @@ statfunc bool vma_is_anon(struct vm_area_struct *vma)
return BPF_CORE_READ(vma, vm_file) == NULL;
}

statfunc bool vma_is_vdso(struct vm_area_struct *vma)
{
struct vm_special_mapping *special_mapping =
(struct vm_special_mapping *) BPF_CORE_READ(vma, vm_private_data);
if (special_mapping == NULL)
return false;

// read only 6 characters (7 with NULL terminator), enough to compare with "[vdso]"
char mapping_name[7];
bpf_probe_read_str(&mapping_name, 7, BPF_CORE_READ(special_mapping, name));
return has_prefix("[vdso]", mapping_name, 6);
}

#endif
3 changes: 2 additions & 1 deletion pkg/ebpf/c/tracee.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -5151,8 +5151,9 @@ statfunc enum vma_type get_vma_type(struct vm_area_struct *vma)
if (vma_is_heap(vma))
return VMA_HEAP;

if (vma_is_anon(vma))
if (vma_is_anon(vma) && !vma_is_vdso(vma)) {
return VMA_ANON;
}

return VMA_OTHER;
}
Expand Down
12 changes: 12 additions & 0 deletions pkg/ebpf/c/vmlinux.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,16 @@ struct rb_node {
struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));

struct vm_area_struct;

struct vm_operations_struct {
const char *(*name)(struct vm_area_struct *vma);
};

struct vm_special_mapping {
const char *name;
};

struct vm_area_struct {
union {
struct {
Expand All @@ -299,7 +309,9 @@ struct vm_area_struct {
struct rb_node vm_rb;
struct mm_struct *vm_mm;
long unsigned int vm_flags;
const struct vm_operations_struct *vm_ops;
struct file *vm_file;
void *vm_private_data;
};

typedef unsigned int __kernel_gid32_t;
Expand Down
7 changes: 5 additions & 2 deletions pkg/ebpf/event_filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (t *Tracee) populateEventFilterMaps() error {
eventFilters := map[string]filters.Filter[*filters.StringFilter]{}
for it := t.config.Policies.CreateAllIterator(); it.HasNext(); {
p := it.Next()
f := p.ArgFilter.GetEventFilters(eventID)
f := p.DataFilter.GetEventFilters(eventID)
if len(f) == 0 {
continue
}
Expand All @@ -41,7 +41,10 @@ func (t *Tracee) populateEventFilterMaps() error {
err := handler(eventFilters, t.bpfModule)
if err != nil {
logger.Errorw("Failed to handle event filter for event " + events.Core.GetDefinitionByID(eventID).GetName() + ", err: " + err.Error())
t.eventsDependencies.RemoveEvent(eventID)
err = t.eventsDependencies.RemoveEvent(eventID)
if err != nil {
return err
}
}
}
return nil
Expand Down
5 changes: 2 additions & 3 deletions pkg/ebpf/initialization/kconfig.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package initialization

import (
"github.com/aquasecurity/libbpfgo/helpers"
"github.com/aquasecurity/tracee/pkg/errfmt"
"github.com/aquasecurity/tracee/pkg/logger"
"github.com/aquasecurity/tracee/pkg/utils/environment"
Expand All @@ -11,7 +10,7 @@ import (
// Add here all kconfig variables used within tracee.bpf.c
const (
CONFIG_ARCH_HAS_SYSCALL_WRAPPER environment.KernelConfigOption = iota + environment.CUSTOM_OPTION_START
CONFIG_MMU helpers.KernelConfigOption = iota + helpers.CUSTOM_OPTION_START
CONFIG_MMU environment.KernelConfigOption = iota + environment.CUSTOM_OPTION_START
)

var kconfigUsed = map[environment.KernelConfigOption]string{
Expand All @@ -36,7 +35,7 @@ func LoadKconfigValues(kc *environment.KernelConfig) (map[environment.KernelConf
values[key] = environment.UNDEFINED
}
values[CONFIG_ARCH_HAS_SYSCALL_WRAPPER] = environment.BUILTIN // assume CONFIG_ARCH_HAS_SYSCALL_WRAPPER is a BUILTIN option
values[CONFIG_MMU] = helpers.BUILTIN // assume CONFIG_MMU is a BUILTIN option
values[CONFIG_MMU] = environment.BUILTIN // assume CONFIG_MMU is a BUILTIN option
} else {
for key := range kconfigUsed {
values[key] = kc.GetValue(key) // undefined, builtin OR module
Expand Down
6 changes: 3 additions & 3 deletions tests/e2e-inst-signatures/e2e-check_syscall_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package main
import (
"fmt"

libbfgo "github.com/aquasecurity/libbpfgo/helpers"
libbpfgo "github.com/aquasecurity/libbpfgo/helpers"

"github.com/aquasecurity/tracee/signatures/helpers"
"github.com/aquasecurity/tracee/types/detect"
Expand All @@ -24,11 +24,11 @@ func (sig *e2eCheckSyscallSource) Init(ctx detect.SignatureContext) error {

// Find if this system uses maple trees to manage VMAs.
// If so we don't expect any check_syscall_source event to be submitted.
ksyms, err := libbfgo.NewKernelSymbolTable()
ksyms, err := libbpfgo.NewKernelSymbolsMap()
if err != nil {
return err
}
_, err = ksyms.GetSymbolByName("mt_find")
_, err = ksyms.GetSymbolByName("system", "mt_find")
if err != nil {
sig.hasMapleTree = false
} else {
Expand Down

0 comments on commit abd31e6

Please sign in to comment.