Skip to content

Commit

Permalink
chore: make policies config versioned
Browse files Browse the repository at this point in the history
This extract the policies related fields from config_entry_t into a
new separate struct (policies_config_t) which continues to be stored in
the config_entry_t struct as well as the versioned policies_config_map.

That is required to be able to access the right policies_config_t based
on the policies version.
  • Loading branch information
geyslan committed Jan 18, 2024
1 parent 8b18657 commit 96b599f
Show file tree
Hide file tree
Showing 7 changed files with 391 additions and 236 deletions.
143 changes: 89 additions & 54 deletions pkg/ebpf/c/common/filtering.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@

// PROTOTYPES

statfunc policies_config_t *get_policies_config(program_data_t *);
statfunc void *get_filter_map(void *, u16);
statfunc u64 uint_filter_range_matches(u64, void *, u64, u64, u64);
statfunc u64 binary_filter_matches(u64, void *, proc_info_t *);
statfunc u64 equality_filter_matches(u64, void *, void *);
statfunc u64 bool_filter_matches(u64, bool val);
statfunc u64 bool_filter_matches(u64, bool);
statfunc u64 compute_scopes(program_data_t *);
statfunc u64 should_trace(program_data_t *);
statfunc u64 should_submit(u32, event_data_t *);
Expand Down Expand Up @@ -51,6 +52,23 @@ statfunc u64 should_submit(u32, event_data_t *);

// FUNCTIONS

statfunc policies_config_t *get_policies_config(program_data_t *p)
{
u16 version = p->event->context.policies_version;

if (likely(version == p->config->policies_version)) {
return &p->config->policies_config;
} else {
policies_config_map_t *policies_config_map;
policies_config_map = bpf_map_lookup_elem(&policies_config_version, &version);
if (unlikely(policies_config_map == NULL))
return NULL;

u32 zero = 0;
return bpf_map_lookup_elem(policies_config_map, &zero);
}
}

// get_filter_map returns the filter map for the given version and outer map
statfunc void *get_filter_map(void *outer_map, u16 version)
{
Expand Down Expand Up @@ -190,147 +208,164 @@ statfunc u64 bool_filter_matches(u64 filter_out_scopes, bool val)
statfunc u64 compute_scopes(program_data_t *p)
{
task_context_t *context = &p->task_info->context;
u64 res = ~0ULL;

// Don't monitor self
if (p->config->tracee_pid == context->host_pid) {
return 0;
}

proc_info_t *proc_info = bpf_map_lookup_elem(&proc_info_map, &context->host_pid);
if (proc_info == NULL) {
if (unlikely(proc_info == NULL)) {
// entry should exist in proc_map (init_program_data should have set it otherwise)
// disable logging as a workaround for instruction limit verifier error on kernel 4.19
// tracee_log(p->event->ctx, BPF_LOG_LVL_WARN, BPF_LOG_ID_MAP_LOOKUP_ELEM, 0);
return 0;
}

policies_config_t *policies_cfg = get_policies_config(p);
if (unlikely(policies_cfg == NULL)) {
// policies_config should be set by userland
return 0;
}

u64 res = ~0ULL;

//
// boolean filters (not using versioned maps)
// boolean filters (not using versioned filter maps)
//

// TODO: Create a filter map for each boolean filter (versioning it) #3805
if (p->config->cont_filter_enabled_scopes) {
if (policies_cfg->cont_filter_enabled_scopes) {
bool is_container = false;
u8 state = p->task_info->container_state;
if (state == CONTAINER_STARTED || state == CONTAINER_EXISTED)
is_container = true;
u64 filter_out_scopes = p->config->cont_filter_out_scopes;
u64 mask = ~p->config->cont_filter_enabled_scopes;
u64 filter_out_scopes = policies_cfg->cont_filter_out_scopes;
u64 mask = ~policies_cfg->cont_filter_enabled_scopes;

// For scopes which has this filter disabled we want to set the matching bits using 'mask'
res &= bool_filter_matches(filter_out_scopes, is_container) | mask;
}

if (p->config->new_cont_filter_enabled_scopes) {
if (policies_cfg->new_cont_filter_enabled_scopes) {
bool is_new_container = false;
if (p->task_info->container_state == CONTAINER_STARTED)
is_new_container = true;
u64 filter_out_scopes = p->config->new_cont_filter_out_scopes;
u64 mask = ~p->config->new_cont_filter_enabled_scopes;
u64 filter_out_scopes = policies_cfg->new_cont_filter_out_scopes;
u64 mask = ~policies_cfg->new_cont_filter_enabled_scopes;

res &= bool_filter_matches(filter_out_scopes, is_new_container) | mask;
}

if (p->config->new_pid_filter_enabled_scopes) {
u64 filter_out_scopes = p->config->new_pid_filter_out_scopes;
u64 mask = ~p->config->new_pid_filter_enabled_scopes;
if (policies_cfg->new_pid_filter_enabled_scopes) {
u64 filter_out_scopes = policies_cfg->new_pid_filter_out_scopes;
u64 mask = ~policies_cfg->new_pid_filter_enabled_scopes;

res &= bool_filter_matches(filter_out_scopes, proc_info->new_proc) | mask;
}

//
// equality filters (using versioned maps)
// equality filters (using versioned filter maps)
//

u16 version = p->event->context.policies_version;
void *filter_map = NULL;

if (p->config->pid_filter_enabled_scopes) {
filter_map = get_filter_map(&pid_filter_version, version);
u64 filter_out_scopes = p->config->pid_filter_out_scopes;
u64 mask = ~p->config->pid_filter_enabled_scopes;
u64 max = p->config->pid_max;
u64 min = p->config->pid_min;
if (policies_cfg->pid_filter_enabled_scopes) {
u64 filter_out_scopes = policies_cfg->pid_filter_out_scopes;
u64 mask = ~policies_cfg->pid_filter_enabled_scopes;
u64 max = policies_cfg->pid_max;
u64 min = policies_cfg->pid_min;

filter_map = get_filter_map(&pid_filter_version, version);
// the user might have given us a tid - check for it too
res &=
uint_filter_range_matches(filter_out_scopes, filter_map, context->host_pid, max, min) |
uint_filter_range_matches(filter_out_scopes, filter_map, context->host_tid, max, min) |
mask;
}

if (p->config->uid_filter_enabled_scopes) {
if (policies_cfg->uid_filter_enabled_scopes) {
u64 filter_out_scopes = policies_cfg->uid_filter_out_scopes;
u64 mask = ~policies_cfg->uid_filter_enabled_scopes;
u64 max = policies_cfg->uid_max;
u64 min = policies_cfg->uid_min;

filter_map = get_filter_map(&uid_filter_version, version);
u64 filter_out_scopes = p->config->uid_filter_out_scopes;
u64 mask = ~p->config->uid_filter_enabled_scopes;
u64 max = p->config->uid_max;
u64 min = p->config->uid_min;
res &=
uint_filter_range_matches(filter_out_scopes, filter_map, context->uid, max, min) | mask;
}

if (p->config->mnt_ns_filter_enabled_scopes) {
filter_map = get_filter_map(&mnt_ns_filter_version, version);
u64 filter_out_scopes = p->config->mnt_ns_filter_out_scopes;
u64 mask = ~p->config->mnt_ns_filter_enabled_scopes;
if (policies_cfg->mnt_ns_filter_enabled_scopes) {
u64 filter_out_scopes = policies_cfg->mnt_ns_filter_out_scopes;
u64 mask = ~policies_cfg->mnt_ns_filter_enabled_scopes;
u64 mnt_id = context->mnt_id;

filter_map = get_filter_map(&mnt_ns_filter_version, version);
res &= equality_filter_matches(filter_out_scopes, filter_map, &mnt_id) | mask;
}

if (p->config->pid_ns_filter_enabled_scopes) {
filter_map = get_filter_map(&pid_ns_filter_version, version);
u64 filter_out_scopes = p->config->pid_ns_filter_out_scopes;
u64 mask = ~p->config->pid_ns_filter_enabled_scopes;
if (policies_cfg->pid_ns_filter_enabled_scopes) {
u64 filter_out_scopes = policies_cfg->pid_ns_filter_out_scopes;
u64 mask = ~policies_cfg->pid_ns_filter_enabled_scopes;
u64 pid_id = context->pid_id;

filter_map = get_filter_map(&pid_ns_filter_version, version);
res &= equality_filter_matches(filter_out_scopes, filter_map, &pid_id) | mask;
}

if (p->config->uts_ns_filter_enabled_scopes) {
if (policies_cfg->uts_ns_filter_enabled_scopes) {
u64 filter_out_scopes = policies_cfg->uts_ns_filter_out_scopes;
u64 mask = ~policies_cfg->uts_ns_filter_enabled_scopes;

filter_map = get_filter_map(&uts_ns_filter_version, version);
u64 filter_out_scopes = p->config->uts_ns_filter_out_scopes;
u64 mask = ~p->config->uts_ns_filter_enabled_scopes;
res &= equality_filter_matches(filter_out_scopes, filter_map, &context->uts_name) | mask;
}

if (p->config->comm_filter_enabled_scopes) {
if (policies_cfg->comm_filter_enabled_scopes) {
u64 filter_out_scopes = policies_cfg->comm_filter_out_scopes;
u64 mask = ~policies_cfg->comm_filter_enabled_scopes;

filter_map = get_filter_map(&comm_filter_version, version);
u64 filter_out_scopes = p->config->comm_filter_out_scopes;
u64 mask = ~p->config->comm_filter_enabled_scopes;
res &= equality_filter_matches(filter_out_scopes, filter_map, &context->comm) | mask;
}

if (p->config->cgroup_id_filter_enabled_scopes) {
filter_map = get_filter_map(&cgroup_id_filter_version, version);
u64 filter_out_scopes = p->config->cgroup_id_filter_out_scopes;
u64 mask = ~p->config->cgroup_id_filter_enabled_scopes;
if (policies_cfg->cgroup_id_filter_enabled_scopes) {
u64 filter_out_scopes = policies_cfg->cgroup_id_filter_out_scopes;
u64 mask = ~policies_cfg->cgroup_id_filter_enabled_scopes;
u32 cgroup_id_lsb = context->cgroup_id;

filter_map = get_filter_map(&cgroup_id_filter_version, version);
res &= equality_filter_matches(filter_out_scopes, filter_map, &cgroup_id_lsb) | mask;
}

if (p->config->proc_tree_filter_enabled_scopes) {
filter_map = get_filter_map(&process_tree_map_version, version);
u64 filter_out_scopes = p->config->proc_tree_filter_out_scopes;
u64 mask = ~p->config->proc_tree_filter_enabled_scopes;
if (policies_cfg->proc_tree_filter_enabled_scopes) {
u64 filter_out_scopes = policies_cfg->proc_tree_filter_out_scopes;
u64 mask = ~policies_cfg->proc_tree_filter_enabled_scopes;
u32 host_pid = context->host_pid;

filter_map = get_filter_map(&process_tree_map_version, version);
res &= equality_filter_matches(filter_out_scopes, filter_map, &host_pid) | mask;
}

if (p->config->bin_path_filter_enabled_scopes) {
if (policies_cfg->bin_path_filter_enabled_scopes) {
u64 filter_out_scopes = policies_cfg->bin_path_filter_out_scopes;
u64 mask = ~policies_cfg->bin_path_filter_enabled_scopes;

filter_map = get_filter_map(&binary_filter_version, version);
u64 filter_out_scopes = p->config->bin_path_filter_out_scopes;
u64 mask = ~p->config->bin_path_filter_enabled_scopes;
res &= binary_filter_matches(filter_out_scopes, filter_map, proc_info) | mask;
}

//
// follow filter
//

if (p->config->follow_filter_enabled_scopes) {
if (policies_cfg->follow_filter_enabled_scopes) {
// trace this proc anyway if follow was set by a scope
res |= proc_info->follow_in_scopes & p->config->follow_filter_enabled_scopes;
res |= proc_info->follow_in_scopes & policies_cfg->follow_filter_enabled_scopes;
}

// Make sure only enabled scopes are set in the bitmask (other bits are invalid)
return res & p->config->enabled_scopes;
return res & policies_cfg->enabled_scopes;
}

statfunc u64 should_trace(program_data_t *p)
Expand Down
18 changes: 18 additions & 0 deletions pkg/ebpf/c/maps.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,24 @@ typedef struct elf_files_map elf_files_map_t;
//

#define MAX_FILTER_VERSION 64 // max amount of filter versions to track
struct policies_config_map {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1);
__type(key, u32);
__type(value, policies_config_t);
} policies_config_map SEC(".maps");

typedef struct policies_config_map policies_config_map_t;

// map of policies config maps
struct policies_config_version {
__uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
__uint(max_entries, MAX_FILTER_VERSION);
__type(key, u16);
__array(values, policies_config_map_t);
} policies_config_version SEC(".maps");

typedef struct policies_config_version policies_config_version_t;

// filter events by UID prototype, for specific UIDs either by == or !=
struct uid_filter {
Expand Down
6 changes: 5 additions & 1 deletion pkg/ebpf/c/tracee.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,11 @@ int tracepoint__sched__sched_process_fork(struct bpf_raw_tracepoint_args *ctx)

// Update the process tree map (filter related) if the parent has an entry.

if (p.config->proc_tree_filter_enabled_scopes) {
policies_config_t *policies_cfg = get_policies_config(&p);
if (unlikely(policies_cfg == NULL))
return 0;

if (policies_cfg->proc_tree_filter_enabled_scopes) {
u16 version = p.event->context.policies_version;
// Give the compiler a hint about the map type, otherwise libbpf will complain
// about missing type information. i.e.: "can't determine value size for type".
Expand Down
16 changes: 10 additions & 6 deletions pkg/ebpf/c/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,12 +287,7 @@ typedef struct equality {
u64 equality_set_in_scopes;
} eq_t;

typedef struct config_entry {
u32 tracee_pid;
u32 options;
u32 cgroup_v1_hid;
u16 policies_version;
u16 padding; // free for further use
typedef struct policies_config {
// enabled scopes bitmask per filter
u64 uid_filter_enabled_scopes;
u64 pid_filter_enabled_scopes;
Expand Down Expand Up @@ -327,6 +322,15 @@ typedef struct config_entry {
u64 uid_min;
u64 pid_max;
u64 pid_min;
} policies_config_t;

typedef struct config_entry {
u32 tracee_pid;
u32 options;
u32 cgroup_v1_hid;
u16 padding; // free for further use
u16 policies_version;
policies_config_t policies_config;
} config_entry_t;

typedef struct event_config {
Expand Down
42 changes: 42 additions & 0 deletions pkg/ebpf/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package ebpf

import (
"unsafe"

bpf "github.com/aquasecurity/libbpfgo"

"github.com/aquasecurity/tracee/pkg/errfmt"
"github.com/aquasecurity/tracee/pkg/policy"
)

const (
ConfigMap = "config_map"
)

// Config mirrors the C struct config_entry (config_entry_t).
//
// Order of fields is important, as it is used as a value for
// the ConfigMap BPF map.
type Config struct {
TraceePid uint32
Options uint32
CgroupV1Hid uint32
_ uint16 // padding free for further use
PoliciesVersion uint16
PoliciesConfig policy.PoliciesConfig
}

// UpdateBPF updates the ConfigMap BPF map with the current config.
func (c *Config) UpdateBPF(bpfModule *bpf.Module) error {
bpfConfigMap, err := bpfModule.GetMap(ConfigMap)
if err != nil {
return errfmt.WrapError(err)
}

cZero := uint32(0)
if err = bpfConfigMap.Update(unsafe.Pointer(&cZero), unsafe.Pointer(c)); err != nil {
return errfmt.WrapError(err)
}

return nil
}
Loading

0 comments on commit 96b599f

Please sign in to comment.