Skip to content
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

[CWS] add kernel bpf filter for raw packet #30288

Merged
merged 35 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5f3a45d
add bpf filter
safchain Oct 16, 2024
42578cc
rework in-kernel
safchain Oct 17, 2024
5c2e049
add map lookup
safchain Oct 18, 2024
51e9148
add bpf to ebpf
safchain Oct 18, 2024
7e647a9
prefix with oo_
safchain Oct 28, 2024
dac26c2
fix update field values
safchain Oct 28, 2024
6f6ee7d
make use of packet.filter
safchain Oct 29, 2024
b891d14
bulk insert
safchain Nov 5, 2024
a05774d
imp comment
safchain Nov 7, 2024
a215cfe
report error and support reload
safchain Nov 8, 2024
60c720e
use dedicated file
safchain Nov 8, 2024
7ce3fce
rename sender prog properly
safchain Nov 8, 2024
35debfa
prepare tail calls
safchain Nov 8, 2024
af2ceb3
fix and test tail calls
safchain Nov 8, 2024
2a3c560
nit fixes
safchain Nov 8, 2024
f16ecae
add max tail calls
safchain Nov 12, 2024
2781508
add unit
safchain Nov 12, 2024
0e84b18
wip ut
safchain Nov 13, 2024
c8d71a7
remove ut for now
safchain Nov 15, 2024
1e62f26
fix commment and linters
safchain Nov 18, 2024
1401c2e
remove pcap dep
safchain Nov 18, 2024
7a8bc2a
decouple pcap part
safchain Nov 18, 2024
e4ac34d
remove _ from the packet name
safchain Nov 18, 2024
82e7ec7
remove rawpacket prefix
safchain Nov 18, 2024
2312a13
re-add raw packet validator
safchain Nov 18, 2024
b032a72
fix bad raw_packet renaming
safchain Nov 19, 2024
f3e3f04
rename no_pcap
safchain Nov 19, 2024
50b0533
re-add ut
safchain Nov 20, 2024
2fcf55b
make pcap available for ut
safchain Nov 20, 2024
3ff1586
skip non supported platform
safchain Nov 20, 2024
52bd8f6
skip 4.14
safchain Nov 21, 2024
2b89b6b
fix raw packet support check
safchain Nov 21, 2024
39ba343
add more ut
safchain Nov 22, 2024
fd0c74f
use 2 differents prog maps
safchain Nov 22, 2024
41b7614
fix overridden
safchain Nov 25, 2024
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
1 change: 1 addition & 0 deletions LICENSE-3rdparty.csv
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,7 @@ core,github.com/cilium/ebpf/perf,MIT,"Copyright (c) 2017 Nathan Sweet | Copyrigh
core,github.com/cilium/ebpf/ringbuf,MIT,"Copyright (c) 2017 Nathan Sweet | Copyright (c) 2018, 2019 Cloudflare | Copyright (c) 2019 Authors of Cilium"
core,github.com/cilium/ebpf/rlimit,MIT,"Copyright (c) 2017 Nathan Sweet | Copyright (c) 2018, 2019 Cloudflare | Copyright (c) 2019 Authors of Cilium"
core,github.com/clbanning/mxj,MIT,Copyright (c) 2012-2016 Charles Banning <clbanning@gmail.com>. All rights reserved | Copyright 2009 The Go Authors. All rights reserved
core,github.com/cloudflare/cbpfc,BSD-3-Clause,"Copyright (c) 2019, Cloudflare. All rights reserved"
core,github.com/cloudflare/circl/dh/x25519,BSD-3-Clause,Copyright (c) 2009 The Go Authors. All rights reserved | Copyright (c) 2019 Cloudflare. All rights reserved
core,github.com/cloudflare/circl/dh/x448,BSD-3-Clause,Copyright (c) 2009 The Go Authors. All rights reserved | Copyright (c) 2019 Cloudflare. All rights reserved
core,github.com/cloudflare/circl/ecc/goldilocks,BSD-3-Clause,Copyright (c) 2009 The Go Authors. All rights reserved | Copyright (c) 2019 Cloudflare. All rights reserved
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ require (
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rs/cors v1.11.1 // indirect
github.com/safchain/baloum v0.0.0-20221229104256-b1fc8f70a86b
github.com/safchain/baloum v0.0.0-20241120122234-f22c9bd19f3b
github.com/saracen/walker v0.1.3 // indirect
github.com/sassoftware/go-rpmutils v0.3.0 // indirect
github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect
Expand Down Expand Up @@ -604,6 +604,7 @@ require (
github.com/DataDog/datadog-agent/pkg/util/defaultpaths v0.0.0-00010101000000-000000000000
github.com/DataDog/datadog-agent/pkg/util/utilizationtracker v0.0.0
github.com/NVIDIA/go-nvml v0.12.4-0
github.com/cloudflare/cbpfc v0.0.0-20240920015331-ff978e94500b
github.com/containerd/containerd/api v1.8.0
github.com/containerd/errdefs v1.0.0
github.com/distribution/reference v0.6.0
Expand Down
6 changes: 4 additions & 2 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions pkg/security/ebpf/c/include/constants/custom.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,14 @@ enum DENTRY_ERPC_RESOLUTION_CODE

enum TC_TAIL_CALL_KEYS
{
UNKNOWN,
DNS_REQUEST,
DNS_REQUEST = 1,
DNS_REQUEST_PARSER,
IMDS_REQUEST,
RAW_PACKET,
};

enum TC_RAWPACKET_KEYS {
RAW_PACKET_FILTER,
// reserved keys for raw packet filter tail calls
};
Comment on lines 70 to 72
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think now that we have two types of tc classifiers, it would probably be best to use two different program maps so that we cannot have key conflits, for example if we want to add new classes of packets in addition to DNS and IMDS and avoid conflicts with programs generated for raw packet filters.


#define DNS_MAX_LENGTH 256
Expand Down
5 changes: 0 additions & 5 deletions pkg/security/ebpf/c/include/helpers/network.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,6 @@ __attribute__((always_inline)) void fill_network_context(struct network_context_
fill_network_device_context(&net_ctx->device, skb, pkt);
}

__attribute__((always_inline)) void tail_call_to_classifier(struct __sk_buff *skb, int classifier_id) {
bpf_tail_call_compat(skb, &classifier_router, classifier_id);
}

__attribute__((always_inline)) void parse_tuple(struct nf_conntrack_tuple *tuple, struct flow_t *flow) {
flow->sport = tuple->src.u.all;
flow->dport = tuple->dst.u.all;
Expand All @@ -94,7 +90,6 @@ __attribute__((always_inline)) void parse_tuple(struct nf_conntrack_tuple *tuple
bpf_probe_read(&flow->daddr, sizeof(flow->daddr), &tuple->dst.u3.all);
}


__attribute__((always_inline)) struct packet_t * parse_packet(struct __sk_buff *skb, int direction) {
struct cursor c = {};
tc_cursor_init(&c, skb);
Expand Down
4 changes: 2 additions & 2 deletions pkg/security/ebpf/c/include/hooks/network/dns.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ int classifier_dns_request(struct __sk_buff *skb) {
evt->id = htons(header.id);

// tail call to the dns request parser
tail_call_to_classifier(skb, DNS_REQUEST_PARSER);
bpf_tail_call_compat(skb, &classifier_router, DNS_REQUEST_PARSER);

// tail call failed, ignore packet
return ACT_OK;
Expand Down Expand Up @@ -116,7 +116,7 @@ int classifier_dns_request_parser(struct __sk_buff *skb) {
send_event_with_size_ptr(skb, EVENT_DNS, evt, offsetof(struct dns_event_t, name) + qname_length);

if (!is_dns_request_parsing_done(skb, pkt)) {
tail_call_to_classifier(skb, DNS_REQUEST_PARSER);
bpf_tail_call_compat(skb, &classifier_router, DNS_REQUEST_PARSER);
}

return ACT_OK;
Expand Down
55 changes: 19 additions & 36 deletions pkg/security/ebpf/c/include/hooks/network/raw.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,44 @@
#include "helpers/network.h"
#include "perf_ring.h"

__attribute__((always_inline)) struct raw_packet_t *get_raw_packet_event() {
__attribute__((always_inline)) struct raw_packet_event_t *get_raw_packet_event() {
u32 key = 0;
return bpf_map_lookup_elem(&raw_packets, &key);
return bpf_map_lookup_elem(&raw_packet_event, &key);
}

SEC("classifier/raw_packet")
int classifier_raw_packet(struct __sk_buff *skb) {
SEC("classifier/raw_packet_sender")
int classifier_raw_packet_sender(struct __sk_buff *skb) {
struct packet_t *pkt = get_packet();
if (pkt == NULL) {
// should never happen
return ACT_OK;
}

struct raw_packet_t *evt = get_raw_packet_event();
if ((evt == NULL) || (skb == NULL)) {
struct raw_packet_event_t *evt = get_raw_packet_event();
if (evt == NULL || skb == NULL || evt->len == 0) {
// should never happen
return ACT_OK;
}

bpf_skb_pull_data(skb, 0);
// process context
fill_network_process_context(&evt->process, pkt);

u32 len = *(u32 *)(skb + offsetof(struct __sk_buff, len));
if (len > sizeof(evt->data)) {
len = sizeof(evt->data);
struct proc_cache_t *entry = get_proc_cache(evt->process.pid);
if (entry == NULL) {
evt->container.container_id[0] = 0;
} else {
copy_container_id_no_tracing(entry->container.container_id, &evt->container.container_id);
}

// NOTE(safchain) inline asm because clang isn't generating the proper instructions for :
// if (len == 0) return ACT_OK;
/*asm ("r4 = %[len]\n"
"if r4 > 0 goto + 2\n"
"r0 = 0\n"
"exit\n" :: [len]"r"((u64)len));*/

if (len > 1) {
if (bpf_skb_load_bytes(skb, 0, evt->data, len) < 0) {
return ACT_OK;
}
evt->len = skb->len;

// process context
fill_network_process_context(&evt->process, pkt);

struct proc_cache_t *entry = get_proc_cache(evt->process.pid);
if (entry == NULL) {
evt->container.container_id[0] = 0;
} else {
copy_container_id_no_tracing(entry->container.container_id, &evt->container.container_id);
}
fill_network_device_context(&evt->device, skb, pkt);

fill_network_device_context(&evt->device, skb, pkt);

u32 size = offsetof(struct raw_packet_t, data) + len;
send_event_with_size_ptr(skb, EVENT_RAW_PACKET, evt, size);
u32 len = evt->len;
if (len > sizeof(evt->data)) {
len = sizeof(evt->data);
}

send_event_with_size_ptr(skb, EVENT_RAW_PACKET, evt, offsetof(struct raw_packet_event_t, data) + len);

return ACT_OK;
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/security/ebpf/c/include/hooks/network/router.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ __attribute__((always_inline)) int route_pkt(struct __sk_buff *skb, struct packe
// route DNS requests
if (is_event_enabled(EVENT_DNS)) {
if (pkt->l4_protocol == IPPROTO_UDP && pkt->translated_ns_flow.flow.dport == htons(53)) {
tail_call_to_classifier(skb, DNS_REQUEST);
bpf_tail_call_compat(skb, &classifier_router, DNS_REQUEST);
}
}

// route IMDS requests
if (is_event_enabled(EVENT_IMDS)) {
if (pkt->l4_protocol == IPPROTO_TCP && ((pkt->ns_flow.flow.saddr[0] & 0xFFFFFFFF) == get_imds_ip() || (pkt->ns_flow.flow.daddr[0] & 0xFFFFFFFF) == get_imds_ip())) {
tail_call_to_classifier(skb, IMDS_REQUEST);
bpf_tail_call_compat(skb, &classifier_router, IMDS_REQUEST);
}
}

Expand Down
39 changes: 37 additions & 2 deletions pkg/security/ebpf/c/include/hooks/network/tc.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,45 @@ int classifier_egress(struct __sk_buff *skb) {
return route_pkt(skb, pkt, EGRESS);
};

__attribute__((always_inline)) int prepare_raw_packet_event(struct __sk_buff *skb) {
struct raw_packet_event_t *evt = get_raw_packet_event();
if (evt == NULL) {
// should never happen
return ACT_OK;
}

bpf_skb_pull_data(skb, 0);

u32 len = *(u32 *)(skb + offsetof(struct __sk_buff, len));
if (len > sizeof(evt->data)) {
len = sizeof(evt->data);
}

if (len > 1) {
if (bpf_skb_load_bytes(skb, 0, evt->data, len) < 0) {
return ACT_OK;
}
evt->len = skb->len;
} else {
evt->len = 0;
}

return ACT_OK;
}


SEC("classifier/ingress")
int classifier_raw_packet_ingress(struct __sk_buff *skb) {
struct packet_t *pkt = parse_packet(skb, INGRESS);
if (!pkt) {
return ACT_OK;
}

tail_call_to_classifier(skb, RAW_PACKET_FILTER);
if (prepare_raw_packet_event(skb) != ACT_OK) {
return ACT_OK;
}

bpf_tail_call_compat(skb, &raw_packet_classifier_router, RAW_PACKET_FILTER);

return ACT_OK;
};
Expand All @@ -45,7 +76,11 @@ int classifier_raw_packet_egress(struct __sk_buff *skb) {
return ACT_OK;
}

tail_call_to_classifier(skb, RAW_PACKET_FILTER);
if (prepare_raw_packet_event(skb) != ACT_OK) {
return ACT_OK;
}

bpf_tail_call_compat(skb, &raw_packet_classifier_router, RAW_PACKET_FILTER);

return ACT_OK;
};
Expand Down
5 changes: 3 additions & 2 deletions pkg/security/ebpf/c/include/maps.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,15 @@ BPF_PERCPU_ARRAY_MAP(packets, struct packet_t, 1)
BPF_PERCPU_ARRAY_MAP(selinux_write_buffer, struct selinux_write_buffer_t, 1)
BPF_PERCPU_ARRAY_MAP(is_new_kthread, u32, 1)
BPF_PERCPU_ARRAY_MAP(syscalls_stats, struct syscalls_stats_t, EVENT_MAX)
BPF_PERCPU_ARRAY_MAP(raw_packets, struct raw_packet_t, 1)
BPF_PERCPU_ARRAY_MAP(raw_packet_event, struct raw_packet_event_t, 1)

BPF_PROG_ARRAY(args_envs_progs, 3)
BPF_PROG_ARRAY(dentry_resolver_kprobe_or_fentry_callbacks, EVENT_MAX)
BPF_PROG_ARRAY(dentry_resolver_tracepoint_callbacks, EVENT_MAX)
BPF_PROG_ARRAY(dentry_resolver_kprobe_or_fentry_progs, 6)
BPF_PROG_ARRAY(dentry_resolver_tracepoint_progs, 3)
BPF_PROG_ARRAY(classifier_router, 100)
BPF_PROG_ARRAY(classifier_router, 10)
BPF_PROG_ARRAY(sys_exit_progs, 64)
BPF_PROG_ARRAY(raw_packet_classifier_router, 32)

#endif
2 changes: 1 addition & 1 deletion pkg/security/ebpf/c/include/structs/network.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ struct network_context_t {
u16 l4_protocol;
};

struct raw_packet_t {
struct raw_packet_event_t {
struct kevent_t event;
struct process_context_t process;
struct span_context_t span;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ int test_ad_ratelimiter_basic() {
assert_zero(activity_dump_rate_limiter_allow(&config, cookie, now, 0),
"event allowed which should not be");
}
return 0;
return 1;
}

SEC("test/ad_ratelimiter_basic_half")
Expand Down Expand Up @@ -73,7 +73,7 @@ int test_ad_ratelimiter_basic_half() {
assert_zero(activity_dump_rate_limiter_allow(&config, cookie, now, 0),
"event allowed which should not be");
}
return 0;
return 1;
}

__attribute__((always_inline)) int test_ad_ratelimiter_variable_droprate(int algo) {
Expand Down Expand Up @@ -106,7 +106,7 @@ __attribute__((always_inline)) int test_ad_ratelimiter_variable_droprate(int alg
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;
return 1;
}

SEC("test/ad_ratelimiter_decreasing_droprate")
Expand Down
1 change: 1 addition & 0 deletions pkg/security/ebpf/c/include/tests/baloum.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ static int (*baloum_call)(struct baloum_ctx *ctx, const char *section) = (void *
static int (*baloum_strcmp)(const char *s1, const char *s2) = (void *)0xfffd;
static int (*baloum_memcmp)(const void *b1, const void *b2, __u32 size) = (void *)0xfffc;
static int (*baloum_sleep)(__u64 ns) = (void *)0xfffb;
static int (*baloum_memcpy)(const void *b1, const void *b2, __u32 size) = (void *)0xfffa;

#define assert_memcmp(b1, b2, s, msg) \
if (baloum_memcmp(b1, b2, s) != 0) { \
Expand Down
8 changes: 4 additions & 4 deletions pkg/security/ebpf/c/include/tests/discarders_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ int test_discarders_event_mask() {
ret = _is_discarded_by_inode(EVENT_CHMOD, mount_id, inode);
assert_not_zero(ret, "inode should be discarded");

return 0;
return 1;
}

SEC("test/discarders_retention")
Expand Down Expand Up @@ -93,7 +93,7 @@ int test_discarders_retention() {
ret = _is_discarded_by_inode(EVENT_OPEN, mount_id, inode);
assert_not_zero(ret, "inode should be discarded");

return 0;
return 1;
}

SEC("test/discarders_revision")
Expand Down Expand Up @@ -142,7 +142,7 @@ int test_discarders_revision() {
ret = _is_discarded_by_inode(EVENT_OPEN, mount_id1, inode1);
assert_not_zero(ret, "inode should be discarded");

return 0;
return 1;
}

SEC("test/discarders_mount_revision")
Expand Down Expand Up @@ -183,7 +183,7 @@ int test_discarders_mount_revision() {
ret = _is_discarded_by_inode(EVENT_OPEN, mount_id1, inode1);
assert_not_zero(ret, "inode should be discarded");

return 0;
return 1;
}

#endif
30 changes: 30 additions & 0 deletions pkg/security/ebpf/c/include/tests/raw_packet_test.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef _RAW_PACKET_TEST_H
#define _RAW_PACKET_TEST_H

#include "helpers/network.h"
#include "baloum.h"

SEC("test/raw_packet_tail_calls")
int raw_packet_tail_calls(struct __sk_buff *skb) {
struct raw_packet_event_t *evt = get_raw_packet_event();
assert_not_null(evt, "unable to get raw packet event")

// tcp dst port 5555 and tcp[tcpflags] == tcp-syn
unsigned char data[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x10,
0x00, 0x30, 0xf4, 0xa2, 0x40, 0x00, 0x40, 0x06,
0x48, 0x13, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00,
0x00, 0x01, 0xa2, 0x36, 0x15, 0xb3, 0x1c, 0x5b,
0x89, 0x33, 0x00, 0x00, 0x00, 0x00, 0x70, 0x02,
0xff, 0xd7, 0xfe, 0x24, 0x00, 0x00, 0x02, 0x04,
0xff, 0xd7, 0x01, 0x03, 0x03, 0x07
};
baloum_memcpy(evt->data, data, sizeof(data));

bpf_tail_call_compat(skb, &raw_packet_classifier_router, RAW_PACKET_FILTER);

return 1;
}

#endif
1 change: 1 addition & 0 deletions pkg/security/ebpf/c/include/tests/tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@

#include "discarders_test.h"
#include "activity_dump_ratelimiter_test.h"
#include "raw_packet_test.h"

#endif
Loading
Loading