From c90d66d511615382231b16b3aa22be6f2d42c15d Mon Sep 17 00:00:00 2001 From: Jonathan Ribas Date: Tue, 6 Dec 2022 11:59:15 +0100 Subject: [PATCH] Add 4 tests, one for each rate limiter algo --- pkg/ebpf/bytecode/runtime/runtime-security.go | 2 +- pkg/security/ebpf/c/activity_dump.h | 2 + .../ebpf/c/activity_dump_ratelimiter_test.h | 128 ++++++++++++++++++ pkg/security/ebpf/c/baloum.h | 30 +++- pkg/security/ebpf/c/discarders.h | 5 +- pkg/security/ebpf/c/tests.h | 3 +- pkg/security/ebpf/c/utils.h | 7 + .../tests/activity_dump_ratelimiter_test.go | 47 +++++++ 8 files changed, 218 insertions(+), 6 deletions(-) create mode 100644 pkg/security/ebpf/c/activity_dump_ratelimiter_test.h create mode 100644 pkg/security/ebpf/c/utils.h create mode 100644 pkg/security/ebpf/tests/activity_dump_ratelimiter_test.go diff --git a/pkg/ebpf/bytecode/runtime/runtime-security.go b/pkg/ebpf/bytecode/runtime/runtime-security.go index 96d1c5c0dee5e..212ef29a2a2a5 100644 --- a/pkg/ebpf/bytecode/runtime/runtime-security.go +++ b/pkg/ebpf/bytecode/runtime/runtime-security.go @@ -4,4 +4,4 @@ package runtime -var RuntimeSecurity = newAsset("runtime-security.c", "284489038bc6dfaa1850e06eb8e909c91bcd6a6a1eaf29233b344f8413361b8e") +var RuntimeSecurity = newAsset("runtime-security.c", "8fc17b02b607a474aa111cd15319ccf7571093c358ca44e3b8a9d413ec8fc7fd") diff --git a/pkg/security/ebpf/c/activity_dump.h b/pkg/security/ebpf/c/activity_dump.h index e626088950d59..28985047d5cc7 100644 --- a/pkg/security/ebpf/c/activity_dump.h +++ b/pkg/security/ebpf/c/activity_dump.h @@ -364,7 +364,9 @@ enum rate_limiter_algo_ids { __attribute__((always_inline)) u8 activity_dump_rate_limiter_reset_period(u64 now, struct activity_dump_rate_limiter_ctx* rate_ctx_p) { rate_ctx_p->current_period = now; rate_ctx_p->counter = 0; +#ifndef __BALOUM__ // do not change algo during unit tests rate_ctx_p->algo_id = now % RL_ALGO_TOTAL_NUMBER; +#endif /* __BALOUM__ */ return 1; } diff --git a/pkg/security/ebpf/c/activity_dump_ratelimiter_test.h b/pkg/security/ebpf/c/activity_dump_ratelimiter_test.h new file mode 100644 index 0000000000000..b0984ff58c9ba --- /dev/null +++ b/pkg/security/ebpf/c/activity_dump_ratelimiter_test.h @@ -0,0 +1,128 @@ +#ifndef _ACTIVITY_DUMP_RATELIMITER_TEST_H_ +#define _ACTIVITY_DUMP_RATELIMITER_TEST_H_ + +#include "defs.h" +#include "activity_dump.h" +#include "baloum.h" +#include "utils.h" + +#define AD_RL_TEST_RATE 500 +#define NUMBER_OF_PERIOD_PER_TEST 10 + +SEC("test/ad_ratelimiter_basic") +int test_ad_ratelimiter_basic() +{ + u64 now = bpf_ktime_get_ns(); + + struct activity_dump_config config; + config.events_rate = AD_RL_TEST_RATE; + + struct activity_dump_rate_limiter_ctx ctx; + ctx.counter = 0; + ctx.current_period = now; + ctx.algo_id = RL_ALGO_BASIC; // force algo basic + u32 cookie = 0; + bpf_map_update_elem(&activity_dump_rate_limiters, &cookie, &ctx, BPF_ANY); + + for (int period_cpt = 0; period_cpt < NUMBER_OF_PERIOD_PER_TEST; period_cpt++, now += SEC_TO_NS(2)) { + assert_not_zero(activity_dump_rate_limiter_allow(&config, cookie, now, 0), + "event not allowed which should be"); + for (int i = 0; i < AD_RL_TEST_RATE; i++) { + assert_not_zero(activity_dump_rate_limiter_allow(&config, cookie, now + i, 1), + "event not allowed which should be"); + } + + assert_zero(activity_dump_rate_limiter_allow(&config, cookie, now, 0), + "event allowed which should not be"); + for (int i = 0; i < AD_RL_TEST_RATE; i++) { + assert_zero(activity_dump_rate_limiter_allow(&config, cookie, now + i, 1), + "event allowed which should not be"); + } + assert_zero(activity_dump_rate_limiter_allow(&config, cookie, now, 0), + "event allowed which should not be"); + } + return 0; +} + +SEC("test/ad_ratelimiter_basic_half") +int test_ad_ratelimiter_basic_half() +{ + u64 now = bpf_ktime_get_ns(); + + struct activity_dump_config config; + config.events_rate = AD_RL_TEST_RATE; + + struct activity_dump_rate_limiter_ctx ctx; + ctx.counter = 0; + ctx.current_period = now; + ctx.algo_id = RL_ALGO_BASIC_HALF; // force algo basic half + u32 cookie = 0; + bpf_map_update_elem(&activity_dump_rate_limiters, &cookie, &ctx, BPF_ANY); + + for (int period_cpt = 0; period_cpt < NUMBER_OF_PERIOD_PER_TEST; period_cpt++, now += SEC_TO_NS(1)) { + assert_not_zero(activity_dump_rate_limiter_allow(&config, cookie, now, 0), + "event not allowed which should be"); + for (int i = 0; i < AD_RL_TEST_RATE / 2; i++) { + assert_not_zero(activity_dump_rate_limiter_allow(&config, cookie, now + i, 1), + "event not allowed which should be"); + } + + assert_zero(activity_dump_rate_limiter_allow(&config, cookie, now, 0), + "event allowed which should not be"); + for (int i = 0; i < AD_RL_TEST_RATE / 2; i++) { + assert_zero(activity_dump_rate_limiter_allow(&config, cookie, now + i, 1), + "event allowed which should not be"); + } + assert_zero(activity_dump_rate_limiter_allow(&config, cookie, now, 0), + "event allowed which should not be"); + } + return 0; +} + +__attribute__((always_inline)) int test_ad_ratelimiter_variable_droprate(int algo) +{ + u64 now = bpf_ktime_get_ns(); + + struct activity_dump_config config; + config.events_rate = AD_RL_TEST_RATE; + + struct activity_dump_rate_limiter_ctx ctx; + ctx.counter = 0; + ctx.current_period = now; + ctx.algo_id = algo; // force algo + u32 cookie = 0; + bpf_map_update_elem(&activity_dump_rate_limiters, &cookie, &ctx, BPF_ANY); + + for (int period_cpt = 0; period_cpt < NUMBER_OF_PERIOD_PER_TEST; period_cpt++, now += SEC_TO_NS(2)) { + assert_not_zero(activity_dump_rate_limiter_allow(&config, cookie, now, 0), + "event not allowed which should be"); + for (int i = 0; i < AD_RL_TEST_RATE / 4; i++) { + assert_not_zero(activity_dump_rate_limiter_allow(&config, cookie, now + i, 1), + "event not allowed which should be"); + } + + int total_allowed = 0; + for (int i = 0; i < AD_RL_TEST_RATE * 10; i++) { + if (activity_dump_rate_limiter_allow(&config, cookie, now + i, 1)) { + total_allowed++; + } + } + assert_greater_than(total_allowed, AD_RL_TEST_RATE * 3 / 4, "nope"); + assert_lesser_than(total_allowed, AD_RL_TEST_RATE / 10, "nope"); + } + return 0; +} + +SEC("test/ad_ratelimiter_decreasing_droprate") +int test_ad_ratelimiter_decreasing_droprate() +{ + return test_ad_ratelimiter_variable_droprate(RL_ALGO_DECREASING_DROPRATE); +} + +SEC("test/ad_ratelimiter_increasing_droprate") +int test_ad_ratelimiter_increasing_droprate() +{ + return test_ad_ratelimiter_variable_droprate(RL_ALGO_INCREASING_DROPRATE); +} + +#endif /* _ACTIVITY_DUMP_RATELIMITER_TEST_H_ */ diff --git a/pkg/security/ebpf/c/baloum.h b/pkg/security/ebpf/c/baloum.h index 03cea27711f68..c4e387808adc9 100644 --- a/pkg/security/ebpf/c/baloum.h +++ b/pkg/security/ebpf/c/baloum.h @@ -59,6 +59,34 @@ static int (*baloum_sleep)(__u64 ns) = (void *)0xfffb; return -1; \ } +#define assert_greater_than(v1, v2, msg) \ + if (v1 > v2) \ + { \ + bpf_printk("assert line %d : v1 == v2 : %s", __LINE__, msg); \ + return -1; \ + } + +#define assert_lesser_than(v1, v2, msg) \ + if (v1 < v2) \ + { \ + bpf_printk("assert line %d : v1 == v2 : %s", __LINE__, msg); \ + return -1; \ + } + +#define assert_greater_or_equal_than(v1, v2, msg) \ + if (v1 >= v2) \ + { \ + bpf_printk("assert line %d : v1 == v2 : %s", __LINE__, msg); \ + return -1; \ + } + +#define assert_lesser_or_equal_than(v1, v2, msg) \ + if (v1 <= v2) \ + { \ + bpf_printk("assert line %d : v1 == v2 : %s", __LINE__, msg); \ + return -1; \ + } + #define assert_not_null(v1, msg) \ if (v1 == NULL) \ { \ @@ -75,4 +103,4 @@ static int (*baloum_sleep)(__u64 ns) = (void *)0xfffb; #endif -#endif \ No newline at end of file +#endif diff --git a/pkg/security/ebpf/c/discarders.h b/pkg/security/ebpf/c/discarders.h index 3f043a23e4a18..4018f452913b0 100644 --- a/pkg/security/ebpf/c/discarders.h +++ b/pkg/security/ebpf/c/discarders.h @@ -1,14 +1,13 @@ #ifndef _DISCARDERS_H #define _DISCARDERS_H +#include "utils.h" + #define REVISION_ARRAY_SIZE 4096 #define INODE_DISCARDER_TYPE 0 #define PID_DISCARDER_TYPE 1 -#define NS_TO_SEC(x) x / 1000000000 -#define SEC_TO_NS(x) x * 1000000000 - struct discarder_stats_t { u64 discarders_added; u64 event_discarded; diff --git a/pkg/security/ebpf/c/tests.h b/pkg/security/ebpf/c/tests.h index e6af9b1fb83e2..9e9652d486857 100644 --- a/pkg/security/ebpf/c/tests.h +++ b/pkg/security/ebpf/c/tests.h @@ -2,5 +2,6 @@ #define _TESTS_H #include "discarders_test.h" +#include "activity_dump_ratelimiter_test.h" -#endif \ No newline at end of file +#endif diff --git a/pkg/security/ebpf/c/utils.h b/pkg/security/ebpf/c/utils.h new file mode 100644 index 0000000000000..4fd4dc6bbb059 --- /dev/null +++ b/pkg/security/ebpf/c/utils.h @@ -0,0 +1,7 @@ +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#define NS_TO_SEC(x) (x) / 1000000000 +#define SEC_TO_NS(x) (x) * 1000000000 + +#endif /* _UTILS_H_ */ diff --git a/pkg/security/ebpf/tests/activity_dump_ratelimiter_test.go b/pkg/security/ebpf/tests/activity_dump_ratelimiter_test.go new file mode 100644 index 0000000000000..277a37e03a427 --- /dev/null +++ b/pkg/security/ebpf/tests/activity_dump_ratelimiter_test.go @@ -0,0 +1,47 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2016-present Datadog, Inc. + +//go:build linux && ebpf_bindata +// +build linux,ebpf_bindata + +package tests + +import ( + "testing" + + "github.com/safchain/baloum/pkg/baloum" +) + +func TestActivityDumpRateLimiterBasic(t *testing.T) { + var ctx baloum.StdContext + code, err := newVM(t).RunProgram(&ctx, "test/ad_ratelimiter_basic") + if err != nil || code != 0 { + t.Errorf("unexpected error: %v, %d", err, code) + } +} + +func TestActivityDumpRateLimiterBasicHalf(t *testing.T) { + var ctx baloum.StdContext + code, err := newVM(t).RunProgram(&ctx, "test/ad_ratelimiter_basic_half") + if err != nil || code != 0 { + t.Errorf("unexpected error: %v, %d", err, code) + } +} + +func TestActivityDumpRateLimiterDecreasingDroprate(t *testing.T) { + var ctx baloum.StdContext + code, err := newVM(t).RunProgram(&ctx, "test/ad_ratelimiter_decreasing_droprate") + if err != nil || code != 0 { + t.Errorf("unexpected error: %v, %d", err, code) + } +} + +func TestActivityDumpRateLimiterIncreasingDroprate(t *testing.T) { + var ctx baloum.StdContext + code, err := newVM(t).RunProgram(&ctx, "test/ad_ratelimiter_increasing_droprate") + if err != nil || code != 0 { + t.Errorf("unexpected error: %v, %d", err, code) + } +}