From fbf16088834708c3c8f7ce6f34d891aaa3e3f38c Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Fri, 6 Sep 2024 14:06:56 -0700 Subject: [PATCH] use skb functions --- GPL/Events/EbpfEventProto.h | 11 +- GPL/Events/Helpers.h | 14 -- GPL/Events/Network/Probe.bpf.c | 220 +++++++---------------- non-GPL/Events/EventsTrace/EventsTrace.c | 14 +- non-GPL/Events/Lib/EbpfEvents.c | 9 +- 5 files changed, 78 insertions(+), 190 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index ed8717a5..804ec1e2 100644 --- a/GPL/Events/EbpfEventProto.h +++ b/GPL/Events/EbpfEventProto.h @@ -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_UDP_SENDMSG = (1 << 20), - EBPF_EVENT_NETWORK_UDP_RECVMSG = (1 << 21), + EBPF_EVENT_NETWORK_SEND_SKB = (1 << 20), + EBPF_EVENT_NETWORK_CONSUME_SKB = (1 << 21), EBPF_EVENT_NETWORK_DNS_PKT = (1 << 22), }; @@ -394,18 +394,13 @@ 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; - struct dns_body pkts[MAX_NR_SEGS]; + uint8_t pkt[MAX_DNS_PACKET]; } __attribute__((packed)); // Basic event statistics diff --git a/GPL/Events/Helpers.h b/GPL/Events/Helpers.h index be6c44d2..b6c2d6bc 100644 --- a/GPL/Events/Helpers.h +++ b/GPL/Events/Helpers.h @@ -367,18 +367,4 @@ 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 diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 5a80e346..5c53bd43 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -20,10 +20,31 @@ DECL_FUNC_RET(inet_csk_accept); -static int sock_dns_event_handle(struct sock *sk, - struct msghdr *msg, - enum ebpf_event_type evt_type, - size_t size) +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) { if (!sk) { return 0; @@ -48,99 +69,37 @@ static int sock_dns_event_handle(struct sock *sk, // filter out non-dns packets if (event->net.dport != 53 && event->net.sport != 53) { + bpf_printk("not a dns packet..."); goto out; } - // 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 - - 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); + // 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; + } - 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; + // udp_send_skb includes the IP and UDP header, so offset + long offset = 0; + if (evt_type == EBPF_EVENT_NETWORK_SEND_SKB) { + offset = 28; } - 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); - } + 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); + goto out; } 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: + bpf_ringbuf_discard(event, 0); return 0; } @@ -148,90 +107,47 @@ static int sock_object_handle(struct sock *sk, enum ebpf_event_type evt_type) =============================== DNS probes =============================== */ -SEC("fentry/udp_sendmsg") -int BPF_PROG(fentry__udp_sendmsg, struct sock *sk, struct msghdr *msg, size_t size) +// 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) { - return sock_dns_event_handle(sk, msg, EBPF_EVENT_NETWORK_UDP_SENDMSG, size); + return handle_consume(skb->sk, skb, skb->len, EBPF_EVENT_NETWORK_SEND_SKB); } -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) +SEC("fentry/skb_consume_udp") +int BPF_PROG(fentry__skb_consume_udp, struct sock *sk, struct sk_buff *skb, int len) { - // check the peeking flag; if set to peek, the msghdr won't contain any data - if (flags & MSG_PEEK) { + // a negative size indicates peeking, ignore + if (len <= 0) { return 0; } - return sock_dns_event_handle(sk, msg, EBPF_EVENT_NETWORK_UDP_RECVMSG, ret); + return handle_consume(sk, skb, len, EBPF_EVENT_NETWORK_CONSUME_SKB); } -SEC("kprobe/udp_sendmsg") -int BPF_KPROBE(kprobe__udp_sendmsg, struct sock *sk, struct msghdr *msg, size_t size) +SEC("kprobe/udp_send_skb") +int BPF_KPROBE(kprobe__udp_send_skb, + struct sk_buff *skb, + struct flowi4 *fl4, + struct inet_cork *cork) { - return sock_dns_event_handle(sk, msg, EBPF_EVENT_NETWORK_UDP_SENDMSG, 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); } -// 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) +SEC("kprobe/skb_consume_udp") +int BPF_KPROBE(kprobe__skb_consume_udp, struct sock *sk, struct sk_buff *skb, int len) { - 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); + // a negative size indicates peeking, ignore + if (len <= 0) { return 0; } - - 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); + return handle_consume(sk, skb, len, EBPF_EVENT_NETWORK_CONSUME_SKB); } /* diff --git a/non-GPL/Events/EventsTrace/EventsTrace.c b/non-GPL/Events/EventsTrace/EventsTrace.c index 6fd41d21..7005e168 100644 --- a/non-GPL/Events/EventsTrace/EventsTrace.c +++ b/non-GPL/Events/EventsTrace/EventsTrace.c @@ -63,8 +63,6 @@ enum cmdline_opts { NETWORK_CONNECTION_ATTEMPTED, NETWORK_CONNECTION_ACCEPTED, NETWORK_CONNECTION_CLOSED, - NETWORK_UDP_SENDMSG, - NETWORK_UDP_RECVMSG, NETWORK_DNS_PKT, CMDLINE_MAX }; @@ -92,8 +90,6 @@ 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 @@ -120,8 +116,6 @@ 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}, @@ -182,8 +176,6 @@ 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; @@ -1082,7 +1074,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->pkts[0].pkt[i]); + printf("%02x ", event->pkt[i]); } printf("\n"); } @@ -1166,10 +1158,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_UDP_SENDMSG: + case EBPF_EVENT_NETWORK_SEND_SKB: out_network_udp_sendmsg((struct ebpf_net_event *)evt_hdr); break; - case EBPF_EVENT_NETWORK_UDP_RECVMSG: + case EBPF_EVENT_NETWORK_CONSUME_SKB: out_network_udp_recvmsg((struct ebpf_net_event *)evt_hdr); break; case EBPF_EVENT_NETWORK_DNS_PKT: diff --git a/non-GPL/Events/Lib/EbpfEvents.c b/non-GPL/Events/Lib/EbpfEvents.c index b325a262..409500cf 100644 --- a/non-GPL/Events/Lib/EbpfEvents.c +++ b/non-GPL/Events/Lib/EbpfEvents.c @@ -386,9 +386,8 @@ static inline int probe_set_autoload(struct btf *btf, struct EventProbe_bpf *obj err = err ?: bpf_program__set_autoload(obj->progs.kretprobe__vfs_write, false); err = err ?: bpf_program__set_autoload(obj->progs.kprobe__chown_common, false); err = err ?: bpf_program__set_autoload(obj->progs.kretprobe__chown_common, false); - err = err ?: bpf_program__set_autoload(obj->progs.kprobe__udp_sendmsg, false); - err = err ?: bpf_program__set_autoload(obj->progs.kprobe__udp_recvmsg, false); - err = err ?: bpf_program__set_autoload(obj->progs.kretprobe__udp_recvmsg, false); + err = err ?: bpf_program__set_autoload(obj->progs.kprobe__udp_send_skb, false); + err = err ?: bpf_program__set_autoload(obj->progs.kprobe__skb_consume_udp, false); } else { err = err ?: bpf_program__set_autoload(obj->progs.fentry__do_unlinkat, false); err = err ?: bpf_program__set_autoload(obj->progs.fentry__mnt_want_write, false); @@ -406,8 +405,8 @@ static inline int probe_set_autoload(struct btf *btf, struct EventProbe_bpf *obj err = err ?: bpf_program__set_autoload(obj->progs.fexit__do_truncate, false); err = err ?: bpf_program__set_autoload(obj->progs.fexit__vfs_write, false); err = err ?: bpf_program__set_autoload(obj->progs.fexit__chown_common, false); - err = err ?: bpf_program__set_autoload(obj->progs.fentry__udp_sendmsg, false); - err = err ?: bpf_program__set_autoload(obj->progs.fexit__udp_recvmsg, false); + err = err ?: bpf_program__set_autoload(obj->progs.fentry__skb_consume_udp, false); + err = err ?: bpf_program__set_autoload(obj->progs.fentry__udp_send_skb, false); } return err;