Skip to content

Commit

Permalink
Revert "use skb functions"
Browse files Browse the repository at this point in the history
This reverts commit fbf1608.
  • Loading branch information
fearful-symmetry committed Sep 9, 2024
1 parent fbf1608 commit 608b1a5
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 78 deletions.
11 changes: 8 additions & 3 deletions GPL/Events/EbpfEventProto.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ 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_SEND_SKB = (1 << 20),
EBPF_EVENT_NETWORK_CONSUME_SKB = (1 << 21),
EBPF_EVENT_NETWORK_UDP_SENDMSG = (1 << 20),
EBPF_EVENT_NETWORK_UDP_RECVMSG = (1 << 21),
EBPF_EVENT_NETWORK_DNS_PKT = (1 << 22),
};

Expand Down Expand Up @@ -394,13 +394,18 @@ struct dns_pkt_header {
uint16_t num_additional_rrs;
} __attribute__((packed));

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

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;
uint8_t pkt[MAX_DNS_PACKET];
struct dns_body pkts[MAX_NR_SEGS];
} __attribute__((packed));

// Basic event statistics
Expand Down
14 changes: 14 additions & 0 deletions GPL/Events/Helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,4 +367,18 @@ static int get_iovec_nr_segs_or_max(struct iov_iter *from)
return nr_segs;
}

struct udp_ctx {
struct sock *sk;
struct msghdr *hdr;
int flags;
} __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
220 changes: 152 additions & 68 deletions GPL/Events/Network/Probe.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,10 @@

DECL_FUNC_RET(inet_csk_accept);

static int sock_object_handle(struct sock *sk, enum ebpf_event_type evt_type)
{
if (!sk)
goto out;
if (ebpf_events_is_trusted_pid())
goto out;

struct ebpf_net_event *event = bpf_ringbuf_reserve(&ringbuf, sizeof(*event), 0);
if (!event)
goto out;

if (ebpf_network_event__fill(event, sk)) {
bpf_ringbuf_discard(event, 0);
goto out;
}

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

out:
return 0;
}

static int
handle_consume(struct sock *sk, struct sk_buff *skb, int len, enum ebpf_event_type evt_type)
static int sock_dns_event_handle(struct sock *sk,
struct msghdr *msg,
enum ebpf_event_type evt_type,
size_t size)
{
if (!sk) {
return 0;
Expand All @@ -69,85 +48,190 @@ handle_consume(struct sock *sk, struct sk_buff *skb, int len, enum ebpf_event_ty

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

// 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;
}
// deal with the iovec_iter type
// newer kernels added a ubuf type to the iov_iter union,
// which post-dates our vmlinux, but also they added ITER_UBUF as the
// first value in the iter_type enum, which makes checking it a tad hard.
// In theory we should be able to read from both types as long as we're careful

// udp_send_skb includes the IP and UDP header, so offset
long offset = 0;
if (evt_type == EBPF_EVENT_NETWORK_SEND_SKB) {
offset = 28;
}
struct iov_iter *from = &msg->msg_iter;

u64 nr_segs = get_iovec_nr_segs_or_max(from);
u64 iovec_size = BPF_CORE_READ(from, count);

unsigned char *data = BPF_CORE_READ(skb, data);
long ret = bpf_probe_read_kernel(event->pkt, readsize, data + offset);
if (ret != 0) {
bpf_printk("error reading in data buffer: %d", ret);
const struct iovec *iov;
if (FIELD_OFFSET(iov_iter, __iov))
iov = (const struct iovec *)((char *)from + FIELD_OFFSET(iov_iter, __iov));
else if (bpf_core_field_exists(from->iov))
iov = BPF_CORE_READ(from, iov);
else {
bpf_printk("unknown offset in iovec structure, bug?");
goto out;
}

if (nr_segs == 1) {
// actually read in raw packet data
// use the retvalue of recvmsg/the count value of sendmsg instead of the the iovec count
// the count of the iovec in udp_recvmsg is the size of the buffer, not the size of the
// bytes read.
void *base = BPF_CORE_READ(iov, iov_base);
event->pkts[0].len = size;
// make verifier happy, we can't have an out-of-bounds write
if (size > MAX_DNS_PACKET) {
bpf_printk("size of packet (%d) exceeds max packet size (%d), skipping", size,
MAX_DNS_PACKET);
goto out;
}
long readok = bpf_probe_read(event->pkts[0].pkt, size, base);
if (readok != 0) {
bpf_printk("invalid read from iovec structure: %d", readok);
goto out;
}
} else {
// we have multiple segments.
// Can't rely on the size value from the function, revert to the iovec size to read into the
// buffer
// In practice, I haven't seen a DNS packet with more than one iovec segment;
// the size of UDP DNS packet is limited to 512 bytes, so not sure if this is possible?
for (int seg = 0; seg < nr_segs; seg++) {
if (seg >= MAX_NR_SEGS)
goto out;

struct iovec *cur_iov = (struct iovec *)&iov[seg];
void *base = BPF_CORE_READ(cur_iov, iov_base);
size_t bufsize = BPF_CORE_READ(cur_iov, iov_len);
event->pkts[seg].len = bufsize;
if (bufsize > sizeof(event->pkts[seg].pkt)) {
goto out;
}
bpf_probe_read(event->pkts[seg].pkt, bufsize, base);
}
}

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

return 0;

out:
bpf_ringbuf_discard(event, 0);
return 0;
}

static int sock_object_handle(struct sock *sk, enum ebpf_event_type evt_type)
{
if (!sk)
goto out;
if (ebpf_events_is_trusted_pid())
goto out;

struct ebpf_net_event *event = bpf_ringbuf_reserve(&ringbuf, sizeof(*event), 0);
if (!event)
goto out;

if (ebpf_network_event__fill(event, sk)) {
bpf_ringbuf_discard(event, 0);
goto out;
}

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

out:
return 0;
}

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

// SEC("fentry/udp_sendmsg")
// int BPF_PROG(fentry__udp_sendmsg, struct sock *sk, struct msghdr *msg, size_t size)
// {
// return sock_dns_event_handle(sk, msg, EBPF_EVENT_NETWORK_UDP_SENDMSG, size);
// }

SEC("fentry/udp_send_skb")
int BPF_PROG(fentry__udp_send_skb, struct sk_buff *skb, struct flowi4 *fl4, struct inet_cork *cork)
SEC("fentry/udp_sendmsg")
int BPF_PROG(fentry__udp_sendmsg, struct sock *sk, struct msghdr *msg, size_t size)
{
return handle_consume(skb->sk, skb, skb->len, EBPF_EVENT_NETWORK_SEND_SKB);
return sock_dns_event_handle(sk, msg, EBPF_EVENT_NETWORK_UDP_SENDMSG, size);
}

SEC("fentry/skb_consume_udp")
int BPF_PROG(fentry__skb_consume_udp, struct sock *sk, struct sk_buff *skb, int len)
SEC("fexit/udp_recvmsg")
int BPF_PROG(fexit__udp_recvmsg,
struct sock *sk,
struct msghdr *msg,
size_t len,
int flags,
int *addr_len,
int ret)
{
// a negative size indicates peeking, ignore
if (len <= 0) {
// check the peeking flag; if set to peek, the msghdr won't contain any data
if (flags & MSG_PEEK) {
return 0;
}
return handle_consume(sk, skb, len, EBPF_EVENT_NETWORK_CONSUME_SKB);
return sock_dns_event_handle(sk, msg, EBPF_EVENT_NETWORK_UDP_RECVMSG, ret);
}

SEC("kprobe/udp_send_skb")
int BPF_KPROBE(kprobe__udp_send_skb,
struct sk_buff *skb,
struct flowi4 *fl4,
struct inet_cork *cork)
SEC("kprobe/udp_sendmsg")
int BPF_KPROBE(kprobe__udp_sendmsg, struct sock *sk, struct msghdr *msg, size_t size)
{
struct sock *sk = BPF_CORE_READ(skb, sk);
unsigned int len = BPF_CORE_READ(skb, len);
return handle_consume(sk, skb, len, EBPF_EVENT_NETWORK_SEND_SKB);
return sock_dns_event_handle(sk, msg, EBPF_EVENT_NETWORK_UDP_SENDMSG, size);
}

SEC("kprobe/skb_consume_udp")
int BPF_KPROBE(kprobe__skb_consume_udp, struct sock *sk, struct sk_buff *skb, int len)
// We can't get the arguments from a kretprobe, so instead save off the pointer in
// in the kprobe, then fetch the pointer from a context map in the kretprobe

SEC("kprobe/udp_recvmsg")
int BPF_KPROBE(
kprobe__udp_recvmsg, struct sock *sk, struct msghdr *msg, size_t len, int flags, int *addr_len)
{
// a negative size indicates peeking, ignore
if (len <= 0) {
struct udp_ctx kctx;
kctx.flags = flags;

// 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.hdr, sizeof(kctx.hdr), &msg);
if (iter_err != 0) {
bpf_printk("error reading msg_iter in udp_recvmsg: %d", iter_err);
return 0;
}
return handle_consume(sk, skb, len, EBPF_EVENT_NETWORK_CONSUME_SKB);

long sk_err = bpf_probe_read(&kctx.sk, sizeof(kctx.sk), &sk);
if (sk_err != 0) {
bpf_printk("error reading msg_iter in udp_recvmsg: %d", sk_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/udp_recvmsg")
int BPF_KRETPROBE(kretprobe__udp_recvmsg, int ret)
{
bpf_printk("in kretprobe udp_recvmsg....");

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 udp_recvmsg: %d", read_err);
}

// check the peeking flag; if set to peek, the msghdr won't contain any data
if (kctx.flags & MSG_PEEK) {
return 0;
}

return sock_dns_event_handle(kctx.sk, kctx.hdr, EBPF_EVENT_NETWORK_UDP_RECVMSG, ret);
}

/*
Expand Down
14 changes: 11 additions & 3 deletions non-GPL/Events/EventsTrace/EventsTrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ enum cmdline_opts {
NETWORK_CONNECTION_ATTEMPTED,
NETWORK_CONNECTION_ACCEPTED,
NETWORK_CONNECTION_CLOSED,
NETWORK_UDP_SENDMSG,
NETWORK_UDP_RECVMSG,
NETWORK_DNS_PKT,
CMDLINE_MAX
};
Expand Down Expand Up @@ -90,6 +92,8 @@ static uint64_t cmdline_to_lib[CMDLINE_MAX] = {
x(NETWORK_CONNECTION_ATTEMPTED)
x(NETWORK_CONNECTION_ACCEPTED)
x(NETWORK_CONNECTION_CLOSED)
x(NETWORK_UDP_SENDMSG)
x(NETWORK_UDP_RECVMSG)
x(NETWORK_DNS_PKT)
#undef x
// clang-format on
Expand All @@ -116,6 +120,8 @@ static const struct argp_option opts[] = {
{"process-load-module", PROCESS_LOAD_MODULE, NULL, false, "Print kernel module load events", 0},
{"net-conn-accept", NETWORK_CONNECTION_ACCEPTED, NULL, false,
"Print network connection accepted events", 0},
{"net-conn-udp-sendmsg", NETWORK_UDP_SENDMSG, NULL, false, "Print udp sendmsg events", 0},
{"net-conn-udp-recvmsg", NETWORK_UDP_RECVMSG, NULL, false, "Print udp recvmsg events", 0},
{"net-conn-dns-pkt", NETWORK_DNS_PKT, NULL, false, "Print DNS events", 0},
{"net-conn-attempt", NETWORK_CONNECTION_ATTEMPTED, NULL, false,
"Print network connection attempted events", 0},
Expand Down Expand Up @@ -176,6 +182,8 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
case NETWORK_CONNECTION_ACCEPTED:
case NETWORK_CONNECTION_ATTEMPTED:
case NETWORK_CONNECTION_CLOSED:
case NETWORK_UDP_SENDMSG:
case NETWORK_UDP_RECVMSG:
case NETWORK_DNS_PKT:
g_events_env |= cmdline_to_lib[key];
break;
Expand Down Expand Up @@ -1074,7 +1082,7 @@ static void out_network_dns_event(struct ebpf_dns_event *event)
// TODO: format as JSON, or just remove?
printf("packet %d: ", event->udp_evt);
for (size_t i = 0; i < 60; i++) {
printf("%02x ", event->pkt[i]);
printf("%02x ", event->pkts[0].pkt[i]);
}
printf("\n");
}
Expand Down Expand Up @@ -1158,10 +1166,10 @@ static int event_ctx_callback(struct ebpf_event_header *evt_hdr)
case EBPF_EVENT_NETWORK_CONNECTION_CLOSED:
out_network_connection_closed_event((struct ebpf_net_event *)evt_hdr);
break;
case EBPF_EVENT_NETWORK_SEND_SKB:
case EBPF_EVENT_NETWORK_UDP_SENDMSG:
out_network_udp_sendmsg((struct ebpf_net_event *)evt_hdr);
break;
case EBPF_EVENT_NETWORK_CONSUME_SKB:
case EBPF_EVENT_NETWORK_UDP_RECVMSG:
out_network_udp_recvmsg((struct ebpf_net_event *)evt_hdr);
break;
case EBPF_EVENT_NETWORK_DNS_PKT:
Expand Down
Loading

0 comments on commit 608b1a5

Please sign in to comment.