Skip to content

Commit

Permalink
cleanup, use proper skbuff offsets
Browse files Browse the repository at this point in the history
  • Loading branch information
fearful-symmetry committed Sep 11, 2024
1 parent c3a53b3 commit 5ce5121
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 162 deletions.
36 changes: 7 additions & 29 deletions GPL/Events/EbpfEventProto.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

#define TASK_COMM_LEN 16
#define MAX_DNS_PACKET 512
#define MAX_NR_SEGS 8

#ifndef __KERNEL__
#include <stdint.h>
Expand Down Expand Up @@ -42,8 +41,6 @@ enum ebpf_event_type {
EBPF_EVENT_PROCESS_SHMGET = (1 << 17),
EBPF_EVENT_PROCESS_PTRACE = (1 << 18),
EBPF_EVENT_PROCESS_LOAD_MODULE = (1 << 19),
EBPF_EVENT_NETWORK_UDP_SEND = (1 << 20),
EBPF_EVENT_NETWORK_UDP_RECV = (1 << 21),
EBPF_EVENT_NETWORK_DNS_PKT = (1 << 22),
};

Expand Down Expand Up @@ -354,6 +351,11 @@ enum ebpf_net_info_af {
EBPF_NETWORK_EVENT_AF_INET6 = 2,
};

enum ebpf_net_udp_info {
EBPF_NETWORK_EVENT_SKB_CONSUME_UDP = 1,
EBPF_NETWORK_EVENT_IP_SEND_UDP = 2,
};

struct ebpf_net_info_tcp_close {
uint64_t bytes_sent;
uint64_t bytes_received;
Expand Down Expand Up @@ -385,42 +387,18 @@ struct ebpf_net_event {
char comm[TASK_COMM_LEN];
} __attribute__((packed));

struct dns_pkt_header {
uint16_t transaction_id;
uint16_t flags;
uint16_t num_questions;
uint16_t num_answers;
uint16_t num_auth_rrs;
uint16_t num_additional_rrs;
} __attribute__((packed));

struct dns_body {
size_t len;
uint8_t pkt[MAX_DNS_PACKET];
} __attribute((packed));

// from vmlinux.h, modified to make the ip addrs u8 arrays
struct skb_iphdr {
uint8_t ihl : 4;
uint8_t version : 4;
uint8_t tos;
uint16_t tot_len;
uint16_t id;
uint16_t frag_off;
uint8_t ttl;
uint8_t protocol;
uint16_t check;
uint8_t saddr[4];
uint8_t daddr[4];
};

struct ebpf_dns_event {
struct ebpf_event_header hdr;
struct ebpf_pid_info pids;
struct ebpf_net_info net;
char comm[TASK_COMM_LEN];
enum ebpf_event_type udp_evt;
struct dns_body pkts[MAX_NR_SEGS];
enum ebpf_net_udp_info udp_evt;
uint8_t pkt[MAX_DNS_PACKET];
} __attribute__((packed));

// Basic event statistics
Expand Down
22 changes: 0 additions & 22 deletions GPL/Events/Helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,6 @@ const volatile int consumer_pid = 0;
// From include/uapi/asm-generic/termbits.h
#define ECHO 0x00008

/* tty_write */
DECL_FIELD_OFFSET(iov_iter, __iov);

static bool IS_ERR_OR_NULL(const void *ptr)
{
return (!ptr) || (unsigned long)ptr >= (unsigned long)-MAX_ERRNO;
Expand Down Expand Up @@ -360,23 +357,4 @@ static int is_equal_prefix(const char *str1, const char *str2, int len)
return !strncmp(str1, str2, len);
}

static int get_iovec_nr_segs_or_max(struct iov_iter *from)
{
u64 nr_segs = BPF_CORE_READ(from, nr_segs);
nr_segs = nr_segs > MAX_NR_SEGS ? MAX_NR_SEGS : nr_segs;
return nr_segs;
}

struct udp_ctx {
struct sk_buff *skb;
} __attribute__((packed));

// scratchspace map for fetching the arguments from a kretprobe
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, u64);
__type(value, struct udp_ctx);
__uint(max_entries, 1024);
} pkt_ctx SEC(".maps");

#endif // EBPF_EVENTPROBE_HELPERS_H
9 changes: 0 additions & 9 deletions GPL/Events/Network/Network.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@

#define MSG_PEEK 2

// See RFC1035
#define DNS_QR_BIT 1 << 15

// I have made this number up to make the verifier happy
#define DNS_MAX_LABELS 255

static int ebpf_sock_info__fill(struct ebpf_net_info *net, struct sock *sk)
{
int err = 0;
Expand Down Expand Up @@ -75,9 +69,6 @@ static int ebpf_sock_info__fill(struct ebpf_net_info *net, struct sock *sk)
case IPPROTO_TCP:
net->transport = EBPF_NETWORK_EVENT_TRANSPORT_TCP;
break;
case IPPROTO_UDP:
net->transport = EBPF_NETWORK_EVENT_TRANSPORT_UDP;
break;
default:
err = -1;
goto out;
Expand Down
123 changes: 40 additions & 83 deletions GPL/Events/Network/Probe.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

DECL_FUNC_RET(inet_csk_accept);

static int sock_object_handle(struct sock *sk, enum ebpf_event_type evt_type)
static int inet_csk_accept__exit(struct sock *sk)
{
if (!sk)
goto out;
Expand All @@ -36,18 +36,14 @@ static int sock_object_handle(struct sock *sk, enum ebpf_event_type evt_type)
goto out;
}

event->hdr.type = evt_type;
event->hdr.type = EBPF_EVENT_NETWORK_CONNECTION_ACCEPTED;
bpf_ringbuf_submit(event, 0);

out:
return 0;
}

/*
=============================== DNS probes ===============================
*/

static int handle_consume(struct sk_buff *skb, int len, enum ebpf_event_type evt_type)
static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type)
{

if (ebpf_events_is_trusted_pid())
Expand All @@ -58,63 +54,65 @@ static int handle_consume(struct sk_buff *skb, int len, enum ebpf_event_type evt
return 0;

// read from skbuf
unsigned char *data = BPF_CORE_READ(skb, head);
unsigned char *skb_head = BPF_CORE_READ(skb, head);
// get lengths
u16 net_header_offset = BPF_CORE_READ(skb, network_header);
u16 transport_header_offset = BPF_CORE_READ(skb, transport_header);

u8 iphdr_first_byte = 0;
bpf_core_read(&iphdr_first_byte, 1, data + net_header_offset);
iphdr_first_byte = iphdr_first_byte >> 4;

u8 proto = 0;
if (iphdr_first_byte == 4) {
struct iphdr ip_hdr;
bpf_core_read(&ip_hdr, sizeof(struct iphdr), data + net_header_offset);

struct iphdr ip_hdr;
bpf_core_read(&ip_hdr, sizeof(struct iphdr), skb_head + net_header_offset);
if (ip_hdr.version == 4) {
proto = ip_hdr.protocol;
bpf_probe_read(event->net.saddr, 4, (void *)&ip_hdr.saddr);
bpf_probe_read(event->net.daddr, 4, (void *)&ip_hdr.daddr);

} else if (iphdr_first_byte == 6) {
bpf_probe_read(event->net.saddr, 4, &ip_hdr.saddr);
bpf_probe_read(event->net.daddr, 4, &ip_hdr.daddr);

event->net.family = EBPF_NETWORK_EVENT_AF_INET;
} else if (ip_hdr.version == 6) {
struct ipv6hdr ip6_hdr;
bpf_core_read(&ip6_hdr, sizeof(struct ipv6hdr), data + net_header_offset);
bpf_core_read(&ip6_hdr, sizeof(struct ipv6hdr), skb_head + net_header_offset);
proto = ip6_hdr.nexthdr;

bpf_probe_read(event->net.saddr6, 16, ip6_hdr.saddr.in6_u.u6_addr8);
bpf_probe_read(event->net.daddr6, 16, ip6_hdr.daddr.in6_u.u6_addr8);

event->net.family = EBPF_NETWORK_EVENT_AF_INET6;
}

if (proto != IPPROTO_UDP) {
goto out;
}

struct udphdr udp_hdr;
bpf_core_read(&udp_hdr, sizeof(struct udphdr), data + transport_header_offset);
event->net.dport = bpf_ntohs(udp_hdr.dest);
event->net.sport = bpf_ntohs(udp_hdr.source);

struct task_struct *task = (struct task_struct *)bpf_get_current_task();
ebpf_pid_info__fill(&event->pids, task);
bpf_get_current_comm(event->comm, TASK_COMM_LEN);
event->hdr.ts = bpf_ktime_get_ns();
bpf_core_read(&udp_hdr, sizeof(struct udphdr), skb_head + transport_header_offset);
event->net.dport = bpf_ntohs(udp_hdr.dest);
event->net.sport = bpf_ntohs(udp_hdr.source);
event->net.transport = EBPF_NETWORK_EVENT_TRANSPORT_UDP;

// filter out non-dns packets
if (event->net.sport != 53 && event->net.dport != 53) {
bpf_printk("not a dns packet...");
goto out;
}

struct task_struct *task = (struct task_struct *)bpf_get_current_task();
ebpf_pid_info__fill(&event->pids, task);
bpf_get_current_comm(event->comm, TASK_COMM_LEN);
event->hdr.ts = bpf_ktime_get_ns();

// constrain the read size to make the verifier happy
long readsize = BPF_CORE_READ(skb, len);
if (readsize > MAX_DNS_PACKET) {
readsize = MAX_DNS_PACKET;
// see skb_headlen() in skbuff.h
size_t readsize = BPF_CORE_READ(skb, len);
size_t datalen = BPF_CORE_READ(skb, data_len);
size_t headlen = readsize - datalen;
bpf_printk("headlen: %lu", readsize - datalen);
if (headlen > MAX_DNS_PACKET) {
headlen = MAX_DNS_PACKET;
}

// udp_send_skb includes the IP and UDP header, so offset
long offset = transport_header_offset + sizeof(struct udphdr);

long ret = bpf_probe_read_kernel(event->pkts[0].pkt, readsize, data + offset);
long ret = bpf_probe_read_kernel(event->pkt, headlen,
skb_head + transport_header_offset + sizeof(struct udphdr));
if (ret != 0) {
bpf_printk("error reading in data buffer: %d", ret);
goto out;
Expand All @@ -134,83 +132,42 @@ static int handle_consume(struct sk_buff *skb, int len, enum ebpf_event_type evt
SEC("fentry/ip_send_skb")
int BPF_PROG(fentry__ip_send_skb, struct net *net, struct sk_buff *skb)
{
return handle_consume(skb, skb->len, EBPF_EVENT_NETWORK_UDP_SEND);
return udp_skb_handle(skb, EBPF_NETWORK_EVENT_IP_SEND_UDP);
}

SEC("fexit/skb_consume_udp")
SEC("fentry/skb_consume_udp")
int BPF_PROG(fexit__skb_consume_udp, struct sock *sk, struct sk_buff *skb, int len)
{
// skip peek operations
bpf_printk("consume len: %d", len);
if (len < 0) {
return 0;
}
return handle_consume(skb, len, EBPF_EVENT_NETWORK_UDP_RECV);
return udp_skb_handle(skb, EBPF_NETWORK_EVENT_SKB_CONSUME_UDP);
}

SEC("kprobe/ip_send_skb")
int BPF_KPROBE(kprobe__ip_send_udp, struct net *net, struct sk_buff *skb)
{
long len = BPF_CORE_READ(skb, len);
return handle_consume(skb, len, EBPF_EVENT_NETWORK_UDP_SEND);
return udp_skb_handle(skb, EBPF_NETWORK_EVENT_IP_SEND_UDP);
}

SEC("kprobe/skb_consume_udp")
int BPF_KPROBE(kprobe__skb_consume_udp, struct net *net, struct sk_buff *skb)
{
// return handle_consume(skb, len, EBPF_EVENT_NETWORK_UDP_SENDMSG);
struct udp_ctx kctx;

// I suspect that using the PID_TID isn't the most reliable way to map the sockets/iters
// not sure what else we could use that's accessable from the kretprobe, though.
u64 pid_tid = bpf_get_current_pid_tgid();

long iter_err = bpf_probe_read(&kctx.skb, sizeof(kctx.skb), &skb);
if (iter_err != 0) {
bpf_printk("error reading skb in skb_consume_skb: %d", iter_err);
return 0;
}

long update_err = bpf_map_update_elem(&pkt_ctx, &pid_tid, &kctx, BPF_ANY);
if (update_err != 0) {
bpf_printk("error updating context map in udp_recvmsg: %d", update_err);
return 0;
}

return 0;
}

SEC("kretprobe/skb_consume_udp")
int BPF_KRETPROBE(kretprobe__skb_consume_udp, int ret)
{
u64 pid_tid = bpf_get_current_pid_tgid();
void *vctx = bpf_map_lookup_elem(&pkt_ctx, &pid_tid);

struct udp_ctx kctx;
long read_err = bpf_probe_read(&kctx, sizeof(kctx), vctx);
if (read_err != 0) {
bpf_printk("error reading back context in skb_consume_skb: %d", read_err);
return 0;
}

return handle_consume(kctx.skb, ret, EBPF_EVENT_NETWORK_UDP_RECV);
return udp_skb_handle(skb, EBPF_NETWORK_EVENT_SKB_CONSUME_UDP);
}

/*
=============================== TCP probes ===============================
*/

SEC("fexit/inet_csk_accept")
int BPF_PROG(fexit__inet_csk_accept)
{
struct sock *ret = FUNC_RET_READ(___type(ret), inet_csk_accept);
return sock_object_handle(ret, EBPF_EVENT_NETWORK_CONNECTION_ACCEPTED);
return inet_csk_accept__exit(ret);
}

SEC("kretprobe/inet_csk_accept")
int BPF_KRETPROBE(kretprobe__inet_csk_accept, struct sock *ret)
{
return sock_object_handle(ret, EBPF_EVENT_NETWORK_CONNECTION_ACCEPTED);
return inet_csk_accept__exit(ret);
}

static int tcp_connect(struct sock *sk, int ret)
Expand Down
8 changes: 7 additions & 1 deletion GPL/Events/Process/Probe.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
#include "State.h"
#include "Varlen.h"

/* tty_write */
DECL_FIELD_OFFSET(iov_iter, __iov);

// Limits on large things we send up as variable length parameters.
//
// These should be kept _well_ under half the size of the event_buffer_map or
Expand Down Expand Up @@ -523,6 +526,8 @@ int BPF_KPROBE(kprobe__commit_creds, struct cred *new)
return commit_creds__enter(new);
}

#define MAX_NR_SEGS 8

static int output_tty_event(struct ebpf_tty_dev *slave, const void *base, size_t base_len)
{
struct ebpf_process_tty_write_event *event;
Expand Down Expand Up @@ -606,7 +611,8 @@ static int tty_write__enter(struct kiocb *iocb, struct iov_iter *from)
else
goto out;

u64 nr_segs = get_iovec_nr_segs_or_max(from);
u64 nr_segs = BPF_CORE_READ(from, nr_segs);
nr_segs = nr_segs > MAX_NR_SEGS ? MAX_NR_SEGS : nr_segs;

if (nr_segs == 0) {
u64 count = BPF_CORE_READ(from, count);
Expand Down
Loading

0 comments on commit 5ce5121

Please sign in to comment.