From d2439084554a0ddf467ba5d906812eea3f31c233 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Fri, 30 Aug 2024 11:15:54 -0700 Subject: [PATCH 01/47] add upd send/recv msg probes --- GPL/Events/EbpfEventProto.h | 3 ++ GPL/Events/Network/Network.h | 3 ++ GPL/Events/Network/Probe.bpf.c | 37 ++++++++++++++++++++---- non-GPL/Events/EventsTrace/EventsTrace.c | 28 ++++++++++++++++++ non-GPL/Events/Lib/EbpfEvents.c | 4 +++ 5 files changed, 69 insertions(+), 6 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index c3919c9e..4f1980bf 100644 --- a/GPL/Events/EbpfEventProto.h +++ b/GPL/Events/EbpfEventProto.h @@ -40,6 +40,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), }; struct ebpf_event_header { @@ -341,6 +343,7 @@ struct ebpf_process_load_module_event { enum ebpf_net_info_transport { EBPF_NETWORK_EVENT_TRANSPORT_TCP = 1, + EBPF_NETWORK_EVENT_TRANSPORT_UDP = 2, }; enum ebpf_net_info_af { diff --git a/GPL/Events/Network/Network.h b/GPL/Events/Network/Network.h index bcb69f28..ec911255 100644 --- a/GPL/Events/Network/Network.h +++ b/GPL/Events/Network/Network.h @@ -67,6 +67,9 @@ 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; diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 6a7f43b0..3f787c54 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -20,40 +20,65 @@ DECL_FUNC_RET(inet_csk_accept); -static int inet_csk_accept__exit(struct sock *sk) +static int sock_object_handle(struct sock *sk, enum ebpf_event_type evt_type) { if (!sk) goto out; - if (ebpf_events_is_trusted_pid()) + 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 = EBPF_EVENT_NETWORK_CONNECTION_ACCEPTED; + event->hdr.type = evt_type; bpf_ringbuf_submit(event, 0); out: return 0; } +SEC("fentry/udp_sendmsg") +int BPF_PROG(fentry__udp_sendmsg, struct sock *sk) +{ + bpf_printk("got ip4_datagram event"); + return sock_object_handle(sk, EBPF_EVENT_NETWORK_UDP_SENDMSG); +} + +SEC("fexit/udp_recvmsg") +int BPF_PROG(fexit__udp_recvmsg, struct sock *sk) +{ + return sock_object_handle(sk, EBPF_EVENT_NETWORK_UDP_RECVMSG); +} + +SEC("kprobe/udp_sendmsg") +int BPF_KPROBE(kprobe__udp_sendmsg, struct sock *sk) +{ + return sock_object_handle(sk, EBPF_EVENT_NETWORK_UDP_SENDMSG); +} + +SEC("kprobe/udp_recvmsg") +int BPF_KPROBE(kprobe__udp_recvmsg, struct sock *sk) +{ + return sock_object_handle(sk, EBPF_EVENT_NETWORK_UDP_RECVMSG); +} + SEC("fexit/inet_csk_accept") int BPF_PROG(fexit__inet_csk_accept) { struct sock *ret = FUNC_RET_READ(___type(ret), inet_csk_accept); - return inet_csk_accept__exit(ret); + return sock_object_handle(ret, EBPF_EVENT_NETWORK_CONNECTION_ACCEPTED); } SEC("kretprobe/inet_csk_accept") int BPF_KRETPROBE(kretprobe__inet_csk_accept, struct sock *ret) { - return inet_csk_accept__exit(ret); + return sock_object_handle(ret, EBPF_EVENT_NETWORK_CONNECTION_ACCEPTED); } static int tcp_connect(struct sock *sk, int ret) diff --git a/non-GPL/Events/EventsTrace/EventsTrace.c b/non-GPL/Events/EventsTrace/EventsTrace.c index 9ff12d05..f9d7f7fc 100644 --- a/non-GPL/Events/EventsTrace/EventsTrace.c +++ b/non-GPL/Events/EventsTrace/EventsTrace.c @@ -63,6 +63,8 @@ enum cmdline_opts { NETWORK_CONNECTION_ATTEMPTED, NETWORK_CONNECTION_ACCEPTED, NETWORK_CONNECTION_CLOSED, + NETWORK_UDP_SENDMSG, + NETWORK_UDP_RECVMSG, CMDLINE_MAX }; @@ -89,6 +91,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) #undef x // clang-format on }; @@ -114,6 +118,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-attempt", NETWORK_CONNECTION_ATTEMPTED, NULL, false, "Print network connection attempted events", 0}, {"net-conn-closed", NETWORK_CONNECTION_CLOSED, NULL, false, @@ -173,6 +179,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: g_events_env |= cmdline_to_lib[key]; break; case ARGP_KEY_ARG: @@ -977,6 +985,10 @@ static void out_net_info(const char *name, struct ebpf_net_event *evt) out_string("transport", "TCP"); out_comma(); break; + case EBPF_NETWORK_EVENT_TRANSPORT_UDP: + out_string("transport", "UDP"); + out_comma(); + break; } switch (net->family) { @@ -1051,6 +1063,16 @@ static void out_network_connection_accepted_event(struct ebpf_net_event *evt) out_network_event("NETWORK_CONNECTION_ACCEPTED", evt); } +static void out_network_udp_sendmsg(struct ebpf_net_event *evnt) +{ + out_network_event("NETWORK_UDP_SENDMSG", evnt); +} + +static void out_network_udp_recvmsg(struct ebpf_net_event *evnt) +{ + out_network_event("NETWORK_UDP_RECVMSG", evnt); +} + static void out_network_connection_attempted_event(struct ebpf_net_event *evt) { out_network_event("NETWORK_CONNECTION_ATTEMPTED", evt); @@ -1130,6 +1152,12 @@ 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: + out_network_udp_sendmsg((struct ebpf_net_event* )evt_hdr); + break; + case EBPF_EVENT_NETWORK_UDP_RECVMSG: + out_network_udp_recvmsg((struct ebpf_net_event *)evt_hdr); + break; } return 0; diff --git a/non-GPL/Events/Lib/EbpfEvents.c b/non-GPL/Events/Lib/EbpfEvents.c index de456775..018ca617 100644 --- a/non-GPL/Events/Lib/EbpfEvents.c +++ b/non-GPL/Events/Lib/EbpfEvents.c @@ -386,6 +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); } 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); @@ -403,6 +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); } return err; From 52bbe58dc0822fe0167437667aa2d5e130639179 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Fri, 30 Aug 2024 11:25:20 -0700 Subject: [PATCH 02/47] format --- GPL/Events/EbpfEventProto.h | 4 ++-- GPL/Events/Network/Probe.bpf.c | 4 ++-- non-GPL/Events/EventsTrace/EventsTrace.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index 4f1980bf..c8ec03ee 100644 --- a/GPL/Events/EbpfEventProto.h +++ b/GPL/Events/EbpfEventProto.h @@ -40,8 +40,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_UDP_SENDMSG = (1 << 20), + EBPF_EVENT_NETWORK_UDP_RECVMSG = (1 << 21), }; struct ebpf_event_header { diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 3f787c54..21af8d85 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -24,13 +24,13 @@ static int sock_object_handle(struct sock *sk, enum ebpf_event_type evt_type) { if (!sk) goto out; - if (ebpf_events_is_trusted_pid()) + 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; diff --git a/non-GPL/Events/EventsTrace/EventsTrace.c b/non-GPL/Events/EventsTrace/EventsTrace.c index f9d7f7fc..17a59cc4 100644 --- a/non-GPL/Events/EventsTrace/EventsTrace.c +++ b/non-GPL/Events/EventsTrace/EventsTrace.c @@ -1153,7 +1153,7 @@ static int event_ctx_callback(struct ebpf_event_header *evt_hdr) out_network_connection_closed_event((struct ebpf_net_event *)evt_hdr); break; case EBPF_EVENT_NETWORK_UDP_SENDMSG: - out_network_udp_sendmsg((struct ebpf_net_event* )evt_hdr); + out_network_udp_sendmsg((struct ebpf_net_event *)evt_hdr); break; case EBPF_EVENT_NETWORK_UDP_RECVMSG: out_network_udp_recvmsg((struct ebpf_net_event *)evt_hdr); From 21af8bb167074520693e558cd52af6385bb44cb9 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Thu, 5 Sep 2024 19:08:14 -0700 Subject: [PATCH 03/47] first pass at DNS packet fetching --- GPL/Events/EbpfEventProto.h | 26 ++++ GPL/Events/Helpers.h | 24 +++ GPL/Events/Network/Network.h | 8 + GPL/Events/Network/Probe.bpf.c | 188 +++++++++++++++++++++-- GPL/Events/Process/Probe.bpf.c | 8 +- non-GPL/Events/EventsTrace/EventsTrace.c | 17 ++ non-GPL/Events/Lib/EbpfEvents.c | 3 +- 7 files changed, 257 insertions(+), 17 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index c8ec03ee..ed8717a5 100644 --- a/GPL/Events/EbpfEventProto.h +++ b/GPL/Events/EbpfEventProto.h @@ -11,6 +11,8 @@ #define EBPF_EVENTPROBE_EBPFEVENTPROTO_H #define TASK_COMM_LEN 16 +#define MAX_DNS_PACKET 512 +#define MAX_NR_SEGS 8 #ifndef __KERNEL__ #include @@ -42,6 +44,7 @@ enum ebpf_event_type { EBPF_EVENT_PROCESS_LOAD_MODULE = (1 << 19), EBPF_EVENT_NETWORK_UDP_SENDMSG = (1 << 20), EBPF_EVENT_NETWORK_UDP_RECVMSG = (1 << 21), + EBPF_EVENT_NETWORK_DNS_PKT = (1 << 22), }; struct ebpf_event_header { @@ -382,6 +385,29 @@ 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)); + +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]; +} __attribute__((packed)); + // Basic event statistics struct ebpf_event_stats { uint64_t lost; // lost events due to a full ringbuffer diff --git a/GPL/Events/Helpers.h b/GPL/Events/Helpers.h index 3844f06e..be6c44d2 100644 --- a/GPL/Events/Helpers.h +++ b/GPL/Events/Helpers.h @@ -138,6 +138,9 @@ 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; @@ -357,4 +360,25 @@ 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 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/Network.h b/GPL/Events/Network/Network.h index ec911255..c3fcd09b 100644 --- a/GPL/Events/Network/Network.h +++ b/GPL/Events/Network/Network.h @@ -14,6 +14,14 @@ #define AF_INET 2 #define AF_INET6 10 +#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; diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 21af8d85..5a80e346 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -20,6 +20,107 @@ 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) +{ + if (!sk) { + return 0; + } + + if (ebpf_events_is_trusted_pid()) + return 0; + + struct ebpf_dns_event *event = bpf_ringbuf_reserve(&ringbuf, sizeof(*event), 0); + if (!event) + return 0; + + // fill in socket and process metadata + if (ebpf_sock_info__fill(&event->net, sk)) { + 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(); + + // filter out non-dns packets + if (event->net.dport != 53 && event->net.sport != 53) { + 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); + + 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) @@ -43,31 +144,100 @@ static int sock_object_handle(struct sock *sk, enum ebpf_event_type evt_type) return 0; } +/* +=============================== DNS probes =============================== +*/ + SEC("fentry/udp_sendmsg") -int BPF_PROG(fentry__udp_sendmsg, struct sock *sk) +int BPF_PROG(fentry__udp_sendmsg, struct sock *sk, struct msghdr *msg, size_t size) { - bpf_printk("got ip4_datagram event"); - return sock_object_handle(sk, EBPF_EVENT_NETWORK_UDP_SENDMSG); + return sock_dns_event_handle(sk, msg, EBPF_EVENT_NETWORK_UDP_SENDMSG, size); } SEC("fexit/udp_recvmsg") -int BPF_PROG(fexit__udp_recvmsg, struct sock *sk) +int BPF_PROG(fexit__udp_recvmsg, + struct sock *sk, + struct msghdr *msg, + size_t len, + int flags, + int *addr_len, + int ret) { - return sock_object_handle(sk, EBPF_EVENT_NETWORK_UDP_RECVMSG); + // check the peeking flag; if set to peek, the msghdr won't contain any data + if (flags & MSG_PEEK) { + return 0; + } + return sock_dns_event_handle(sk, msg, EBPF_EVENT_NETWORK_UDP_RECVMSG, ret); } SEC("kprobe/udp_sendmsg") -int BPF_KPROBE(kprobe__udp_sendmsg, struct sock *sk) +int BPF_KPROBE(kprobe__udp_sendmsg, struct sock *sk, struct msghdr *msg, size_t size) { - return sock_object_handle(sk, EBPF_EVENT_NETWORK_UDP_SENDMSG); + return sock_dns_event_handle(sk, msg, EBPF_EVENT_NETWORK_UDP_SENDMSG, size); } +// 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) +int BPF_KPROBE( + kprobe__udp_recvmsg, struct sock *sk, struct msghdr *msg, size_t len, int flags, int *addr_len) { - return sock_object_handle(sk, EBPF_EVENT_NETWORK_UDP_RECVMSG); + 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; + } + + 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); +} + +/* +=============================== TCP probes =============================== +*/ + SEC("fexit/inet_csk_accept") int BPF_PROG(fexit__inet_csk_accept) { diff --git a/GPL/Events/Process/Probe.bpf.c b/GPL/Events/Process/Probe.bpf.c index 8970943f..8122c15b 100644 --- a/GPL/Events/Process/Probe.bpf.c +++ b/GPL/Events/Process/Probe.bpf.c @@ -18,9 +18,6 @@ #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 @@ -526,8 +523,6 @@ 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; @@ -611,8 +606,7 @@ static int tty_write__enter(struct kiocb *iocb, struct iov_iter *from) else goto out; - u64 nr_segs = BPF_CORE_READ(from, nr_segs); - nr_segs = nr_segs > MAX_NR_SEGS ? MAX_NR_SEGS : nr_segs; + u64 nr_segs = get_iovec_nr_segs_or_max(from); if (nr_segs == 0) { u64 count = BPF_CORE_READ(from, count); diff --git a/non-GPL/Events/EventsTrace/EventsTrace.c b/non-GPL/Events/EventsTrace/EventsTrace.c index 17a59cc4..6fd41d21 100644 --- a/non-GPL/Events/EventsTrace/EventsTrace.c +++ b/non-GPL/Events/EventsTrace/EventsTrace.c @@ -65,6 +65,7 @@ enum cmdline_opts { NETWORK_CONNECTION_CLOSED, NETWORK_UDP_SENDMSG, NETWORK_UDP_RECVMSG, + NETWORK_DNS_PKT, CMDLINE_MAX }; @@ -93,6 +94,7 @@ static uint64_t cmdline_to_lib[CMDLINE_MAX] = { x(NETWORK_CONNECTION_CLOSED) x(NETWORK_UDP_SENDMSG) x(NETWORK_UDP_RECVMSG) + x(NETWORK_DNS_PKT) #undef x // clang-format on }; @@ -120,6 +122,7 @@ static const struct argp_option opts[] = { "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}, {"net-conn-closed", NETWORK_CONNECTION_CLOSED, NULL, false, @@ -181,6 +184,7 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) case NETWORK_CONNECTION_CLOSED: case NETWORK_UDP_SENDMSG: case NETWORK_UDP_RECVMSG: + case NETWORK_DNS_PKT: g_events_env |= cmdline_to_lib[key]; break; case ARGP_KEY_ARG: @@ -1073,6 +1077,16 @@ static void out_network_udp_recvmsg(struct ebpf_net_event *evnt) out_network_event("NETWORK_UDP_RECVMSG", evnt); } +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("\n"); +} + static void out_network_connection_attempted_event(struct ebpf_net_event *evt) { out_network_event("NETWORK_CONNECTION_ATTEMPTED", evt); @@ -1158,6 +1172,9 @@ static int event_ctx_callback(struct ebpf_event_header *evt_hdr) case EBPF_EVENT_NETWORK_UDP_RECVMSG: out_network_udp_recvmsg((struct ebpf_net_event *)evt_hdr); break; + case EBPF_EVENT_NETWORK_DNS_PKT: + out_network_dns_event((struct ebpf_dns_event *)evt_hdr); + break; } return 0; diff --git a/non-GPL/Events/Lib/EbpfEvents.c b/non-GPL/Events/Lib/EbpfEvents.c index 018ca617..b325a262 100644 --- a/non-GPL/Events/Lib/EbpfEvents.c +++ b/non-GPL/Events/Lib/EbpfEvents.c @@ -388,6 +388,7 @@ static inline int probe_set_autoload(struct btf *btf, struct EventProbe_bpf *obj 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); } 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); @@ -942,4 +943,4 @@ int ebpf_set_process_trustlist(struct bpf_map *map, uint32_t *pids, int count) } return rv; -} +} \ No newline at end of file From fbf16088834708c3c8f7ce6f34d891aaa3e3f38c Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Fri, 6 Sep 2024 14:06:56 -0700 Subject: [PATCH 04/47] 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; From 608b1a5284b87509b2fbd0b4767d761600404979 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Mon, 9 Sep 2024 09:59:34 -0700 Subject: [PATCH 05/47] Revert "use skb functions" This reverts commit fbf16088834708c3c8f7ce6f34d891aaa3e3f38c. --- 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, 190 insertions(+), 78 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index 804ec1e2..ed8717a5 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_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), }; @@ -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 diff --git a/GPL/Events/Helpers.h b/GPL/Events/Helpers.h index b6c2d6bc..be6c44d2 100644 --- a/GPL/Events/Helpers.h +++ b/GPL/Events/Helpers.h @@ -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 diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 5c53bd43..5a80e346 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -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; @@ -69,33 +48,72 @@ 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: @@ -103,51 +121,117 @@ handle_consume(struct sock *sk, struct sk_buff *skb, int len, enum ebpf_event_ty 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); } /* diff --git a/non-GPL/Events/EventsTrace/EventsTrace.c b/non-GPL/Events/EventsTrace/EventsTrace.c index 7005e168..6fd41d21 100644 --- a/non-GPL/Events/EventsTrace/EventsTrace.c +++ b/non-GPL/Events/EventsTrace/EventsTrace.c @@ -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 }; @@ -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 @@ -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}, @@ -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; @@ -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"); } @@ -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: diff --git a/non-GPL/Events/Lib/EbpfEvents.c b/non-GPL/Events/Lib/EbpfEvents.c index 409500cf..b325a262 100644 --- a/non-GPL/Events/Lib/EbpfEvents.c +++ b/non-GPL/Events/Lib/EbpfEvents.c @@ -386,8 +386,9 @@ 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_send_skb, false); - err = err ?: bpf_program__set_autoload(obj->progs.kprobe__skb_consume_udp, 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); } 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); @@ -405,8 +406,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__skb_consume_udp, false); - err = err ?: bpf_program__set_autoload(obj->progs.fentry__udp_send_skb, 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); } return err; From b8c65593886b720709ac7d78192c7a89fdb0842b Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Mon, 9 Sep 2024 14:19:26 -0700 Subject: [PATCH 06/47] try to make recvmsg portable --- GPL/Events/Network/Probe.bpf.c | 45 ++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 5a80e346..177039fc 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -74,8 +74,8 @@ static int sock_dns_event_handle(struct sock *sk, 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 + // 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; @@ -155,18 +155,33 @@ int BPF_PROG(fentry__udp_sendmsg, struct sock *sk, struct msghdr *msg, size_t si } 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) +int BPF_PROG(fexit__udp_recvmsg) { + + // 5.18 changed the function args for udp_recvmsg, + // so we have to do this to fetch the value of the `flags` arg. + // obviously if the args change again this can fail. + u64 flags = 0; + u64 nr_args = bpf_get_func_arg_cnt(ctx); + if (nr_args == 5) { + bpf_get_func_arg(ctx, 3, &flags); + } else if (nr_args == 6) { + bpf_get_func_arg(ctx, 4, &flags); + } // check the peeking flag; if set to peek, the msghdr won't contain any data + // Still trying to get this to work portably. if (flags & MSG_PEEK) { return 0; } + // bpf_get_func_arg_cnt() + struct sock *sk = (void *)ctx[0]; + struct msghdr *msg = (void *)ctx[1]; + u64 ret = 0; + bpf_get_func_ret(ctx, &ret); + u16 family = BPF_CORE_READ(sk, __sk_common.skc_family); + // struct msghdr* msg = (struct msghdr*)PT_REGS_PARM2(regs); + bpf_printk("retval: %d", regs_ret); + // return 0; return sock_dns_event_handle(sk, msg, EBPF_EVENT_NETWORK_UDP_RECVMSG, ret); } @@ -180,11 +195,9 @@ int BPF_KPROBE(kprobe__udp_sendmsg, struct sock *sk, struct msghdr *msg, size_t // 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) +int BPF_KPROBE(kprobe__udp_recvmsg, struct sock *sk, struct msghdr *msg) { 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. @@ -217,8 +230,7 @@ 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); + void *vctx = bpf_map_lookup_elem(&pkt_ctx, &pid_tid); struct udp_ctx kctx; long read_err = bpf_probe_read(&kctx, sizeof(kctx), vctx); @@ -226,11 +238,6 @@ int BPF_KRETPROBE(kretprobe__udp_recvmsg, int ret) 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); } From 58bb331ed91514c2260ea4e34190dd7ee7d60b14 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Mon, 9 Sep 2024 15:02:59 -0700 Subject: [PATCH 07/47] only use kprobes for udp methods, pray this works --- GPL/Events/Network/Probe.bpf.c | 40 +++------------------------------ non-GPL/Events/Lib/EbpfEvents.c | 5 ----- 2 files changed, 3 insertions(+), 42 deletions(-) diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 177039fc..b8f6f53e 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -85,6 +85,9 @@ static int sock_dns_event_handle(struct sock *sk, MAX_DNS_PACKET); goto out; } + // TODO: This will fail on recvmsg calls where the peek flag has been set. + // Changes to the udp_recvmsg function call in 5.18 make it a bit annoying to get the + // flags argument portably. So let it fail instead of manually skipping peek calls. long readok = bpf_probe_read(event->pkts[0].pkt, size, base); if (readok != 0) { bpf_printk("invalid read from iovec structure: %d", readok); @@ -148,43 +151,6 @@ 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) -{ - return sock_dns_event_handle(sk, msg, EBPF_EVENT_NETWORK_UDP_SENDMSG, size); -} - -SEC("fexit/udp_recvmsg") -int BPF_PROG(fexit__udp_recvmsg) -{ - - // 5.18 changed the function args for udp_recvmsg, - // so we have to do this to fetch the value of the `flags` arg. - // obviously if the args change again this can fail. - u64 flags = 0; - u64 nr_args = bpf_get_func_arg_cnt(ctx); - if (nr_args == 5) { - bpf_get_func_arg(ctx, 3, &flags); - } else if (nr_args == 6) { - bpf_get_func_arg(ctx, 4, &flags); - } - // check the peeking flag; if set to peek, the msghdr won't contain any data - // Still trying to get this to work portably. - if (flags & MSG_PEEK) { - return 0; - } - // bpf_get_func_arg_cnt() - struct sock *sk = (void *)ctx[0]; - struct msghdr *msg = (void *)ctx[1]; - u64 ret = 0; - bpf_get_func_ret(ctx, &ret); - u16 family = BPF_CORE_READ(sk, __sk_common.skc_family); - // struct msghdr* msg = (struct msghdr*)PT_REGS_PARM2(regs); - bpf_printk("retval: %d", regs_ret); - // return 0; - return sock_dns_event_handle(sk, msg, EBPF_EVENT_NETWORK_UDP_RECVMSG, ret); -} - SEC("kprobe/udp_sendmsg") int BPF_KPROBE(kprobe__udp_sendmsg, struct sock *sk, struct msghdr *msg, size_t size) { diff --git a/non-GPL/Events/Lib/EbpfEvents.c b/non-GPL/Events/Lib/EbpfEvents.c index b325a262..3daeb8e9 100644 --- a/non-GPL/Events/Lib/EbpfEvents.c +++ b/non-GPL/Events/Lib/EbpfEvents.c @@ -386,9 +386,6 @@ 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); } 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 +403,6 @@ 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); } return err; From 5527d1373653c8f8caeb67523051ffb28250b917 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Mon, 9 Sep 2024 15:19:35 -0700 Subject: [PATCH 08/47] verifier logic has changed? --- GPL/Events/Helpers.h | 1 - 1 file changed, 1 deletion(-) diff --git a/GPL/Events/Helpers.h b/GPL/Events/Helpers.h index be6c44d2..fffffa46 100644 --- a/GPL/Events/Helpers.h +++ b/GPL/Events/Helpers.h @@ -370,7 +370,6 @@ static int get_iovec_nr_segs_or_max(struct iov_iter *from) struct udp_ctx { struct sock *sk; struct msghdr *hdr; - int flags; } __attribute__((packed)); // scratchspace map for fetching the arguments from a kretprobe From 06d83276201c131de0961fbc1c3e26c1a2c8df4c Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Tue, 10 Sep 2024 09:46:22 -0700 Subject: [PATCH 09/47] testing skb methods --- GPL/Events/Network/Probe.bpf.c | 82 +++++++++++++++++++++++++++++++++ non-GPL/Events/Lib/EbpfEvents.c | 7 +++ 2 files changed, 89 insertions(+) diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index b8f6f53e..2f7021d0 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -147,6 +147,88 @@ static int sock_object_handle(struct sock *sk, enum ebpf_event_type evt_type) return 0; } +/* +=============================== TEST CODE =============================== + +Testing alternate code. This section will not be merged, or will be cleaned up. +*/ + +static int +handle_consume(struct sock *sk, struct sk_buff *skb, int len, enum ebpf_event_type evt_type) +{ + if (!sk) { + return 0; + } + + if (ebpf_events_is_trusted_pid()) + return 0; + + struct ebpf_dns_event *event = bpf_ringbuf_reserve(&ringbuf, sizeof(*event), 0); + if (!event) + return 0; + + // fill in socket and process metadata + if (ebpf_sock_info__fill(&event->net, sk)) { + 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(); + + // 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; + } + + // udp_send_skb includes the IP and UDP header, so offset + long offset = 0; + if (evt_type == EBPF_EVENT_NETWORK_UDP_SENDMSG) { + offset = 28; + } + + unsigned char *data = BPF_CORE_READ(skb, data); + long ret = bpf_probe_read_kernel(event->pkts[0].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; +} + +SEC("fentry/ip_send_skb") +int BPF_PROG(fentry__ip_send_skb, struct net *net, struct sk_buff *skb) +{ + return handle_consume(skb->sk, skb, skb->len, EBPF_EVENT_NETWORK_UDP_SENDMSG); +} + +SEC("fexit/skb_consume_udp") +int BPF_PROG(fexit__skb_consume_udp, struct sock *sk, struct sk_buff *skb, int len) +{ + // skip peek operations + if (len < 0) { + return 0; + } + return handle_consume(sk, skb, len, EBPF_EVENT_NETWORK_UDP_RECVMSG); +} + /* =============================== DNS probes =============================== */ diff --git a/non-GPL/Events/Lib/EbpfEvents.c b/non-GPL/Events/Lib/EbpfEvents.c index 3daeb8e9..ab4d9f1c 100644 --- a/non-GPL/Events/Lib/EbpfEvents.c +++ b/non-GPL/Events/Lib/EbpfEvents.c @@ -386,6 +386,10 @@ 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); + + // TEST CODE + err = err ?: bpf_program__set_autoload(obj->progs.kprobe__udp_sendmsg, false); + err = err ?: bpf_program__set_autoload(obj->progs.kprobe__udp_recvmsg, 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); @@ -403,6 +407,9 @@ 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__ip_send_skb, false); + err = err ?: bpf_program__set_autoload(obj->progs.fexit__skb_consume_udp, false); } return err; From 5aa36cd2b1d61fe236fd1f60f50d6d3a40c1432f Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Tue, 10 Sep 2024 13:10:21 -0700 Subject: [PATCH 10/47] clean up skb code --- GPL/Events/EbpfEventProto.h | 15 +++++++++++ GPL/Events/Network/Probe.bpf.c | 45 +++++++++++++++++++++++++-------- non-GPL/Events/Lib/EbpfEvents.c | 1 + 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index ed8717a5..58130a55 100644 --- a/GPL/Events/EbpfEventProto.h +++ b/GPL/Events/EbpfEventProto.h @@ -399,6 +399,21 @@ struct dns_body { 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; diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 2f7021d0..0e071d7f 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -167,18 +167,47 @@ handle_consume(struct sock *sk, struct sk_buff *skb, int len, enum ebpf_event_ty if (!event) return 0; - // fill in socket and process metadata - if (ebpf_sock_info__fill(&event->net, sk)) { + // read from skbuf + unsigned char *data = BPF_CORE_READ(skb, head); + + u8 iphdr_first_byte = 0; + bpf_core_read(&iphdr_first_byte, 1, data + skb->network_header); + 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 + skb->network_header); + + 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) { + struct ipv6hdr ip6_hdr; + bpf_core_read(&ip6_hdr, sizeof(struct ipv6hdr), data + skb->network_header); + 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); + } + + if (proto != IPPROTO_UDP) { goto out; } + struct udphdr udp_hdr; + bpf_core_read(&udp_hdr, sizeof(struct udphdr), data + skb->transport_header); + 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(); // filter out non-dns packets - if (event->net.dport != 53 && event->net.sport != 53) { + if (event->net.sport != 53 && event->net.dport != 53) { bpf_printk("not a dns packet..."); goto out; } @@ -190,13 +219,9 @@ handle_consume(struct sock *sk, struct sk_buff *skb, int len, enum ebpf_event_ty } // udp_send_skb includes the IP and UDP header, so offset - long offset = 0; - if (evt_type == EBPF_EVENT_NETWORK_UDP_SENDMSG) { - offset = 28; - } + long offset = skb->transport_header + sizeof(struct udphdr); - unsigned char *data = BPF_CORE_READ(skb, data); - long ret = bpf_probe_read_kernel(event->pkts[0].pkt, readsize, data + offset); + long ret = bpf_probe_read_kernel(event->pkts[0].pkt, readsize, data + offset); if (ret != 0) { bpf_printk("error reading in data buffer: %d", ret); goto out; @@ -223,6 +248,7 @@ SEC("fexit/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; } @@ -275,7 +301,6 @@ int BPF_KPROBE(kprobe__udp_recvmsg, struct sock *sk, struct msghdr *msg) 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); diff --git a/non-GPL/Events/Lib/EbpfEvents.c b/non-GPL/Events/Lib/EbpfEvents.c index ab4d9f1c..c5073679 100644 --- a/non-GPL/Events/Lib/EbpfEvents.c +++ b/non-GPL/Events/Lib/EbpfEvents.c @@ -390,6 +390,7 @@ static inline int probe_set_autoload(struct btf *btf, struct EventProbe_bpf *obj // TEST CODE 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); } 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); From 049b2c1592b9db6abb14822fca388bc8edf55cd9 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Tue, 10 Sep 2024 13:12:22 -0700 Subject: [PATCH 11/47] format --- GPL/Events/Network/Probe.bpf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 0e071d7f..9bb654fa 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -180,8 +180,8 @@ handle_consume(struct sock *sk, struct sk_buff *skb, int len, enum ebpf_event_ty bpf_core_read(&ip_hdr, sizeof(struct iphdr), data + skb->network_header); 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); + 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) { struct ipv6hdr ip6_hdr; From d8c7e25f11a9006615ab23ebc470003fdd113a3a Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Tue, 10 Sep 2024 14:02:43 -0700 Subject: [PATCH 12/47] still testing --- GPL/Events/Helpers.h | 5 +- GPL/Events/Network/Probe.bpf.c | 122 ++++++++++++++++++++++---------- non-GPL/Events/Lib/EbpfEvents.c | 9 +-- 3 files changed, 89 insertions(+), 47 deletions(-) diff --git a/GPL/Events/Helpers.h b/GPL/Events/Helpers.h index fffffa46..12f90a85 100644 --- a/GPL/Events/Helpers.h +++ b/GPL/Events/Helpers.h @@ -368,8 +368,9 @@ static int get_iovec_nr_segs_or_max(struct iov_iter *from) } struct udp_ctx { - struct sock *sk; - struct msghdr *hdr; + // struct sock *sk; + // struct msghdr *hdr; + struct sk_buf *skb; } __attribute__((packed)); // scratchspace map for fetching the arguments from a kretprobe diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 9bb654fa..82c686d7 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -153,12 +153,8 @@ static int sock_object_handle(struct sock *sk, enum ebpf_event_type evt_type) Testing alternate code. This section will not be merged, or will be cleaned up. */ -static int -handle_consume(struct sock *sk, struct sk_buff *skb, int len, enum ebpf_event_type evt_type) +static int handle_consume(struct sk_buff *skb, int len, enum ebpf_event_type evt_type) { - if (!sk) { - return 0; - } if (ebpf_events_is_trusted_pid()) return 0; @@ -169,15 +165,18 @@ handle_consume(struct sock *sk, struct sk_buff *skb, int len, enum ebpf_event_ty // read from skbuf unsigned char *data = 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 + skb->network_header); + 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 + skb->network_header); + bpf_core_read(&ip_hdr, sizeof(struct iphdr), data + net_header_offset); proto = ip_hdr.protocol; bpf_probe_read(event->net.saddr, 4, (void *)&ip_hdr.saddr); @@ -185,7 +184,7 @@ handle_consume(struct sock *sk, struct sk_buff *skb, int len, enum ebpf_event_ty } else if (iphdr_first_byte == 6) { struct ipv6hdr ip6_hdr; - bpf_core_read(&ip6_hdr, sizeof(struct ipv6hdr), data + skb->network_header); + bpf_core_read(&ip6_hdr, sizeof(struct ipv6hdr), data + net_header_offset); proto = ip6_hdr.nexthdr; bpf_probe_read(event->net.saddr6, 16, ip6_hdr.saddr.in6_u.u6_addr8); @@ -197,7 +196,7 @@ handle_consume(struct sock *sk, struct sk_buff *skb, int len, enum ebpf_event_ty } struct udphdr udp_hdr; - bpf_core_read(&udp_hdr, sizeof(struct udphdr), data + skb->transport_header); + 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); @@ -219,7 +218,7 @@ handle_consume(struct sock *sk, struct sk_buff *skb, int len, enum ebpf_event_ty } // udp_send_skb includes the IP and UDP header, so offset - long offset = skb->transport_header + sizeof(struct udphdr); + long offset = transport_header_offset + sizeof(struct udphdr); long ret = bpf_probe_read_kernel(event->pkts[0].pkt, readsize, data + offset); if (ret != 0) { @@ -241,7 +240,7 @@ handle_consume(struct sock *sk, struct sk_buff *skb, int len, enum ebpf_event_ty SEC("fentry/ip_send_skb") int BPF_PROG(fentry__ip_send_skb, struct net *net, struct sk_buff *skb) { - return handle_consume(skb->sk, skb, skb->len, EBPF_EVENT_NETWORK_UDP_SENDMSG); + return handle_consume(skb, skb->len, EBPF_EVENT_NETWORK_UDP_SENDMSG); } SEC("fexit/skb_consume_udp") @@ -252,40 +251,29 @@ int BPF_PROG(fexit__skb_consume_udp, struct sock *sk, struct sk_buff *skb, int l if (len < 0) { return 0; } - return handle_consume(sk, skb, len, EBPF_EVENT_NETWORK_UDP_RECVMSG); + return handle_consume(skb, len, EBPF_EVENT_NETWORK_UDP_RECVMSG); } -/* -=============================== DNS probes =============================== -*/ - -SEC("kprobe/udp_sendmsg") -int BPF_KPROBE(kprobe__udp_sendmsg, struct sock *sk, struct msghdr *msg, size_t size) +SEC("kprobe/ip_send_skb") +int BPF_KPROBE(kprobe__ip_send_skb, struct net *net, struct sk_buff *skb) { - return sock_dns_event_handle(sk, msg, EBPF_EVENT_NETWORK_UDP_SENDMSG, size); + long len = BPF_CORE_READ(skb, len); + return handle_consume(skb, len, EBPF_EVENT_NETWORK_UDP_SENDMSG); } -// 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) +SEC("kprobe/skb_consume_skb") +int BPF_KPROBE(kprobe__skb_consume_skb, 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.hdr, sizeof(kctx.hdr), &msg); + long iter_err = bpf_probe_read(&kctx.skb, sizeof(kctx.skb), &skb); if (iter_err != 0) { - bpf_printk("error reading msg_iter in udp_recvmsg: %d", iter_err); - 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); + bpf_printk("error reading skb in skb_consume_skb: %d", iter_err); return 0; } @@ -294,26 +282,82 @@ int BPF_KPROBE(kprobe__udp_recvmsg, struct sock *sk, struct msghdr *msg) 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) +SEC("kretprobe/skb_consume_skb") +int BPF_KRETPROBE(kretprobe__skb_consume_skb, 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 udp_recvmsg: %d", read_err); + bpf_printk("error reading back context in skb_consume_skb: %d", read_err); } - return sock_dns_event_handle(kctx.sk, kctx.hdr, EBPF_EVENT_NETWORK_UDP_RECVMSG, ret); + return handle_consume(kctx.skb, ret, EBPF_EVENT_NETWORK_UDP_RECVMSG); +} + +/* +=============================== DNS probes =============================== +*/ + +SEC("kprobe/udp_sendmsg") +int BPF_KPROBE(kprobe__udp_sendmsg, struct sock *sk, struct msghdr *msg, size_t size) +{ + return sock_dns_event_handle(sk, msg, EBPF_EVENT_NETWORK_UDP_SENDMSG, size); } +// 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) +// { +// 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.hdr, sizeof(kctx.hdr), &msg); +// if (iter_err != 0) { +// bpf_printk("error reading msg_iter in udp_recvmsg: %d", iter_err); +// 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) +// { + +// 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); +// } + +// return sock_dns_event_handle(kctx.sk, kctx.hdr, EBPF_EVENT_NETWORK_UDP_RECVMSG, ret); +// } + /* =============================== TCP probes =============================== */ diff --git a/non-GPL/Events/Lib/EbpfEvents.c b/non-GPL/Events/Lib/EbpfEvents.c index c5073679..15c09b7a 100644 --- a/non-GPL/Events/Lib/EbpfEvents.c +++ b/non-GPL/Events/Lib/EbpfEvents.c @@ -386,11 +386,9 @@ 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); - - // TEST CODE - 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__ip_send_skb, false); + err = err ?: bpf_program__set_autoload(obj->progs.kprobe__skb_consume_skb, false); + err = err ?: bpf_program__set_autoload(obj->progs.kretprobe__skb_consume_skb, 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); @@ -408,7 +406,6 @@ 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__ip_send_skb, false); err = err ?: bpf_program__set_autoload(obj->progs.fexit__skb_consume_udp, false); } From 40fa09a9f3f1e3754df4c62a804e101267859ac5 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Tue, 10 Sep 2024 14:18:14 -0700 Subject: [PATCH 13/47] typo --- GPL/Events/Network/Probe.bpf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 82c686d7..18bc0bd6 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -261,7 +261,7 @@ int BPF_KPROBE(kprobe__ip_send_skb, struct net *net, struct sk_buff *skb) return handle_consume(skb, len, EBPF_EVENT_NETWORK_UDP_SENDMSG); } -SEC("kprobe/skb_consume_skb") +SEC("kprobe/skb_consume_udp") int BPF_KPROBE(kprobe__skb_consume_skb, struct net *net, struct sk_buff *skb) { // return handle_consume(skb, len, EBPF_EVENT_NETWORK_UDP_SENDMSG); @@ -284,7 +284,7 @@ int BPF_KPROBE(kprobe__skb_consume_skb, struct net *net, struct sk_buff *skb) } } -SEC("kretprobe/skb_consume_skb") +SEC("kretprobe/skb_consume_udp") int BPF_KRETPROBE(kretprobe__skb_consume_skb, int ret) { u64 pid_tid = bpf_get_current_pid_tgid(); From 54771127d70d2e903def017c08add57262f84fb0 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Tue, 10 Sep 2024 14:28:35 -0700 Subject: [PATCH 14/47] still cleaning up test code --- GPL/Events/Helpers.h | 2 +- GPL/Events/Network/Probe.bpf.c | 9 ++++++--- non-GPL/Events/Lib/EbpfEvents.c | 6 +++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/GPL/Events/Helpers.h b/GPL/Events/Helpers.h index 12f90a85..f4fb7cff 100644 --- a/GPL/Events/Helpers.h +++ b/GPL/Events/Helpers.h @@ -370,7 +370,7 @@ static int get_iovec_nr_segs_or_max(struct iov_iter *from) struct udp_ctx { // struct sock *sk; // struct msghdr *hdr; - struct sk_buf *skb; + struct sk_buff *skb; } __attribute__((packed)); // scratchspace map for fetching the arguments from a kretprobe diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 18bc0bd6..d64e4e55 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -255,14 +255,14 @@ int BPF_PROG(fexit__skb_consume_udp, struct sock *sk, struct sk_buff *skb, int l } SEC("kprobe/ip_send_skb") -int BPF_KPROBE(kprobe__ip_send_skb, struct net *net, struct sk_buff *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_SENDMSG); } SEC("kprobe/skb_consume_udp") -int BPF_KPROBE(kprobe__skb_consume_skb, struct net *net, struct sk_buff *skb) +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; @@ -282,10 +282,12 @@ int BPF_KPROBE(kprobe__skb_consume_skb, struct net *net, struct sk_buff *skb) 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_skb, int ret) +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); @@ -294,6 +296,7 @@ int BPF_KRETPROBE(kretprobe__skb_consume_skb, int ret) 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_RECVMSG); diff --git a/non-GPL/Events/Lib/EbpfEvents.c b/non-GPL/Events/Lib/EbpfEvents.c index 15c09b7a..0b20f2ee 100644 --- a/non-GPL/Events/Lib/EbpfEvents.c +++ b/non-GPL/Events/Lib/EbpfEvents.c @@ -386,9 +386,9 @@ 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__ip_send_skb, false); - err = err ?: bpf_program__set_autoload(obj->progs.kprobe__skb_consume_skb, false); - err = err ?: bpf_program__set_autoload(obj->progs.kretprobe__skb_consume_skb, false); + err = err ?: bpf_program__set_autoload(obj->progs.kprobe__ip_send_udp, false); + err = err ?: bpf_program__set_autoload(obj->progs.kprobe__skb_consume_udp, false); + err = err ?: bpf_program__set_autoload(obj->progs.kretprobe__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); From d2770ff24d41adc8c664eff2896fcbe8e76c2a63 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Tue, 10 Sep 2024 14:44:26 -0700 Subject: [PATCH 15/47] cleanup --- GPL/Events/Helpers.h | 2 - GPL/Events/Network/Probe.bpf.c | 167 +-------------------------------- 2 files changed, 1 insertion(+), 168 deletions(-) diff --git a/GPL/Events/Helpers.h b/GPL/Events/Helpers.h index f4fb7cff..eb7db92b 100644 --- a/GPL/Events/Helpers.h +++ b/GPL/Events/Helpers.h @@ -368,8 +368,6 @@ static int get_iovec_nr_segs_or_max(struct iov_iter *from) } struct udp_ctx { - // struct sock *sk; - // struct msghdr *hdr; struct sk_buff *skb; } __attribute__((packed)); diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index d64e4e55..51cd3a03 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -20,110 +20,6 @@ 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) -{ - if (!sk) { - return 0; - } - - if (ebpf_events_is_trusted_pid()) - return 0; - - struct ebpf_dns_event *event = bpf_ringbuf_reserve(&ringbuf, sizeof(*event), 0); - if (!event) - return 0; - - // fill in socket and process metadata - if (ebpf_sock_info__fill(&event->net, sk)) { - 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(); - - // filter out non-dns packets - if (event->net.dport != 53 && event->net.sport != 53) { - 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); - - 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; - } - // TODO: This will fail on recvmsg calls where the peek flag has been set. - // Changes to the udp_recvmsg function call in 5.18 make it a bit annoying to get the - // flags argument portably. So let it fail instead of manually skipping peek calls. - 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) @@ -148,9 +44,7 @@ static int sock_object_handle(struct sock *sk, enum ebpf_event_type evt_type) } /* -=============================== TEST CODE =============================== - -Testing alternate code. This section will not be merged, or will be cleaned up. +=============================== DNS probes =============================== */ static int handle_consume(struct sk_buff *skb, int len, enum ebpf_event_type evt_type) @@ -302,65 +196,6 @@ int BPF_KRETPROBE(kretprobe__skb_consume_udp, int ret) return handle_consume(kctx.skb, ret, EBPF_EVENT_NETWORK_UDP_RECVMSG); } -/* -=============================== DNS probes =============================== -*/ - -SEC("kprobe/udp_sendmsg") -int BPF_KPROBE(kprobe__udp_sendmsg, struct sock *sk, struct msghdr *msg, size_t size) -{ - return sock_dns_event_handle(sk, msg, EBPF_EVENT_NETWORK_UDP_SENDMSG, size); -} - -// 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) -// { -// 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.hdr, sizeof(kctx.hdr), &msg); -// if (iter_err != 0) { -// bpf_printk("error reading msg_iter in udp_recvmsg: %d", iter_err); -// 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) -// { - -// 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); -// } - -// return sock_dns_event_handle(kctx.sk, kctx.hdr, EBPF_EVENT_NETWORK_UDP_RECVMSG, ret); -// } - /* =============================== TCP probes =============================== */ From 17a5e4d552724e951a292e9a380fbfc6f4f952bd Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Tue, 10 Sep 2024 18:29:51 -0700 Subject: [PATCH 16/47] rename enums --- GPL/Events/EbpfEventProto.h | 4 ++-- GPL/Events/Network/Probe.bpf.c | 8 ++++---- non-GPL/Events/EventsTrace/EventsTrace.c | 12 ++---------- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index 58130a55..54e18de0 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_UDP_SEND = (1 << 20), + EBPF_EVENT_NETWORK_UDP_RECV = (1 << 21), EBPF_EVENT_NETWORK_DNS_PKT = (1 << 22), }; diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 51cd3a03..902721ee 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -134,7 +134,7 @@ 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_SENDMSG); + return handle_consume(skb, skb->len, EBPF_EVENT_NETWORK_UDP_SEND); } SEC("fexit/skb_consume_udp") @@ -145,14 +145,14 @@ int BPF_PROG(fexit__skb_consume_udp, struct sock *sk, struct sk_buff *skb, int l if (len < 0) { return 0; } - return handle_consume(skb, len, EBPF_EVENT_NETWORK_UDP_RECVMSG); + return handle_consume(skb, len, EBPF_EVENT_NETWORK_UDP_RECV); } 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_SENDMSG); + return handle_consume(skb, len, EBPF_EVENT_NETWORK_UDP_SEND); } SEC("kprobe/skb_consume_udp") @@ -193,7 +193,7 @@ int BPF_KRETPROBE(kretprobe__skb_consume_udp, int ret) return 0; } - return handle_consume(kctx.skb, ret, EBPF_EVENT_NETWORK_UDP_RECVMSG); + return handle_consume(kctx.skb, ret, EBPF_EVENT_NETWORK_UDP_RECV); } /* diff --git a/non-GPL/Events/EventsTrace/EventsTrace.c b/non-GPL/Events/EventsTrace/EventsTrace.c index 6fd41d21..f5d96e72 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; @@ -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_UDP_SEND: out_network_udp_sendmsg((struct ebpf_net_event *)evt_hdr); break; - case EBPF_EVENT_NETWORK_UDP_RECVMSG: + case EBPF_EVENT_NETWORK_UDP_RECV: out_network_udp_recvmsg((struct ebpf_net_event *)evt_hdr); break; case EBPF_EVENT_NETWORK_DNS_PKT: From c3a53b35f15ca692961d5011d15a0dfbfaa57604 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Tue, 10 Sep 2024 18:32:18 -0700 Subject: [PATCH 17/47] format --- GPL/Events/EbpfEventProto.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index 54e18de0..7540e57a 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_SEND = (1 << 20), - EBPF_EVENT_NETWORK_UDP_RECV = (1 << 21), + EBPF_EVENT_NETWORK_UDP_SEND = (1 << 20), + EBPF_EVENT_NETWORK_UDP_RECV = (1 << 21), EBPF_EVENT_NETWORK_DNS_PKT = (1 << 22), }; From 5ce512156e772fdeb6552f1381de2ba0a9baf87a Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 11 Sep 2024 09:17:45 -0700 Subject: [PATCH 18/47] cleanup, use proper skbuff offsets --- GPL/Events/EbpfEventProto.h | 36 ++----- GPL/Events/Helpers.h | 22 ---- GPL/Events/Network/Network.h | 9 -- GPL/Events/Network/Probe.bpf.c | 123 ++++++++--------------- GPL/Events/Process/Probe.bpf.c | 8 +- non-GPL/Events/EventsTrace/EventsTrace.c | 18 +--- non-GPL/Events/Lib/EbpfEvents.c | 1 - 7 files changed, 55 insertions(+), 162 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index 7540e57a..afcece54 100644 --- a/GPL/Events/EbpfEventProto.h +++ b/GPL/Events/EbpfEventProto.h @@ -12,7 +12,6 @@ #define TASK_COMM_LEN 16 #define MAX_DNS_PACKET 512 -#define MAX_NR_SEGS 8 #ifndef __KERNEL__ #include @@ -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), }; @@ -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; @@ -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 diff --git a/GPL/Events/Helpers.h b/GPL/Events/Helpers.h index eb7db92b..3844f06e 100644 --- a/GPL/Events/Helpers.h +++ b/GPL/Events/Helpers.h @@ -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; @@ -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 diff --git a/GPL/Events/Network/Network.h b/GPL/Events/Network/Network.h index c3fcd09b..c584b6e9 100644 --- a/GPL/Events/Network/Network.h +++ b/GPL/Events/Network/Network.h @@ -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; @@ -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; diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 902721ee..befc403e 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -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; @@ -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()) @@ -58,31 +54,31 @@ 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) { @@ -90,31 +86,33 @@ static int handle_consume(struct sk_buff *skb, int len, enum ebpf_event_type evt } 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; @@ -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) diff --git a/GPL/Events/Process/Probe.bpf.c b/GPL/Events/Process/Probe.bpf.c index 8122c15b..8970943f 100644 --- a/GPL/Events/Process/Probe.bpf.c +++ b/GPL/Events/Process/Probe.bpf.c @@ -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 @@ -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; @@ -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); diff --git a/non-GPL/Events/EventsTrace/EventsTrace.c b/non-GPL/Events/EventsTrace/EventsTrace.c index f5d96e72..69a3fb17 100644 --- a/non-GPL/Events/EventsTrace/EventsTrace.c +++ b/non-GPL/Events/EventsTrace/EventsTrace.c @@ -1059,22 +1059,12 @@ static void out_network_connection_accepted_event(struct ebpf_net_event *evt) out_network_event("NETWORK_CONNECTION_ACCEPTED", evt); } -static void out_network_udp_sendmsg(struct ebpf_net_event *evnt) -{ - out_network_event("NETWORK_UDP_SENDMSG", evnt); -} - -static void out_network_udp_recvmsg(struct ebpf_net_event *evnt) -{ - out_network_event("NETWORK_UDP_RECVMSG", evnt); -} - 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"); } @@ -1158,12 +1148,6 @@ 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_SEND: - out_network_udp_sendmsg((struct ebpf_net_event *)evt_hdr); - break; - case EBPF_EVENT_NETWORK_UDP_RECV: - out_network_udp_recvmsg((struct ebpf_net_event *)evt_hdr); - break; case EBPF_EVENT_NETWORK_DNS_PKT: out_network_dns_event((struct ebpf_dns_event *)evt_hdr); break; diff --git a/non-GPL/Events/Lib/EbpfEvents.c b/non-GPL/Events/Lib/EbpfEvents.c index 0b20f2ee..13955de8 100644 --- a/non-GPL/Events/Lib/EbpfEvents.c +++ b/non-GPL/Events/Lib/EbpfEvents.c @@ -388,7 +388,6 @@ static inline int probe_set_autoload(struct btf *btf, struct EventProbe_bpf *obj err = err ?: bpf_program__set_autoload(obj->progs.kretprobe__chown_common, false); err = err ?: bpf_program__set_autoload(obj->progs.kprobe__ip_send_udp, false); err = err ?: bpf_program__set_autoload(obj->progs.kprobe__skb_consume_udp, false); - err = err ?: bpf_program__set_autoload(obj->progs.kretprobe__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); From 067fe9e1bc9a32955c0481b4ea2e1d4682fdb5c2 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 11 Sep 2024 10:34:42 -0700 Subject: [PATCH 19/47] use varlen for packet body --- GPL/Events/EbpfEventProto.h | 10 +++++++++- GPL/Events/Network/Probe.bpf.c | 14 +++++++++----- non-GPL/Events/EventsTrace/EventsTrace.c | 15 ++++++++++----- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index afcece54..eb401124 100644 --- a/GPL/Events/EbpfEventProto.h +++ b/GPL/Events/EbpfEventProto.h @@ -11,6 +11,11 @@ #define EBPF_EVENTPROBE_EBPFEVENTPROTO_H #define TASK_COMM_LEN 16 +// The theoretical max size of DNS packets over UDP +// Like so many things in DNS this number probaby isn't 100% accurate. +// DNS extensions in RFC2671 and RFC6891 mean the actual size can be larger, +// although an additonal body over 512 is probably due to additional RR fields, +// which we can (probably) get away with throwing out for now. #define MAX_DNS_PACKET 512 #ifndef __KERNEL__ @@ -68,6 +73,7 @@ enum ebpf_varlen_field_type { EBPF_VL_FIELD_SYMLINK_TARGET_PATH, EBPF_VL_FIELD_MOD_VERSION, EBPF_VL_FIELD_MOD_SRCVERSION, + EBPF_VL_FIELD_DNS_BODY, }; // Convenience macro to iterate all the variable length fields in an event @@ -398,7 +404,9 @@ struct ebpf_dns_event { struct ebpf_net_info net; char comm[TASK_COMM_LEN]; enum ebpf_net_udp_info udp_evt; - uint8_t pkt[MAX_DNS_PACKET]; + // Variable length fields: dns body + struct ebpf_varlen_fields_start vl_fields; + // uint8_t pkt[MAX_DNS_PACKET]; } __attribute__((packed)); // Basic event statistics diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index befc403e..3b849a90 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -17,6 +17,7 @@ #include "Helpers.h" #include "Network.h" #include "State.h" +#include "Varlen.h" DECL_FUNC_RET(inet_csk_accept); @@ -49,7 +50,7 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) if (ebpf_events_is_trusted_pid()) return 0; - struct ebpf_dns_event *event = bpf_ringbuf_reserve(&ringbuf, sizeof(*event), 0); + struct ebpf_dns_event *event = get_event_buffer(); if (!event) return 0; @@ -106,26 +107,29 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) 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; } - long ret = bpf_probe_read_kernel(event->pkt, headlen, + ebpf_vl_fields__init(&event->vl_fields); + struct ebpf_varlen_field *field; + field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_DNS_BODY); + + long ret = bpf_probe_read_kernel(field->data, headlen, skb_head + transport_header_offset + sizeof(struct udphdr)); if (ret != 0) { bpf_printk("error reading in data buffer: %d", ret); goto out; } + ebpf_vl_field__set_size(&event->vl_fields, field, headlen); event->hdr.type = EBPF_EVENT_NETWORK_DNS_PKT; event->udp_evt = evt_type; - bpf_ringbuf_submit(event, 0); + ebpf_ringbuf_write(&ringbuf, event, EVENT_SIZE(event), 0); return 0; out: - bpf_ringbuf_discard(event, 0); return 0; } diff --git a/non-GPL/Events/EventsTrace/EventsTrace.c b/non-GPL/Events/EventsTrace/EventsTrace.c index 69a3fb17..0cfb5bcb 100644 --- a/non-GPL/Events/EventsTrace/EventsTrace.c +++ b/non-GPL/Events/EventsTrace/EventsTrace.c @@ -1061,12 +1061,17 @@ static void out_network_connection_accepted_event(struct ebpf_net_event *evt) 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]); + struct ebpf_varlen_field *field; + FOR_EACH_VARLEN_FIELD(event->vl_fields, field) + { + // TODO: format as JSON, or just remove? + printf("packet %d: ", event->udp_evt); + for (size_t i = 0; i < field->size; i++) { + uint8_t part = field->data[i]; + printf("%02X ", part); + } + printf("\n"); } - printf("\n"); } static void out_network_connection_attempted_event(struct ebpf_net_event *evt) From 30bc829fed2093ac5c6548f0d3a0f6549fdcfcbc Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 11 Sep 2024 10:49:13 -0700 Subject: [PATCH 20/47] use json for output --- non-GPL/Events/EventsTrace/EventsTrace.c | 30 +++++++++++++++++++----- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/non-GPL/Events/EventsTrace/EventsTrace.c b/non-GPL/Events/EventsTrace/EventsTrace.c index 0cfb5bcb..edd6a753 100644 --- a/non-GPL/Events/EventsTrace/EventsTrace.c +++ b/non-GPL/Events/EventsTrace/EventsTrace.c @@ -969,9 +969,8 @@ static void out_ip6_addr(const char *name, const void *addr) printf("\"%s\":\"%s\"", name, buf); } -static void out_net_info(const char *name, struct ebpf_net_event *evt) +static void out_net_info(const char *name, struct ebpf_net_info *net, struct ebpf_event_header *hdr) { - struct ebpf_net_info *net = &evt->net; printf("\"%s\":", name); out_object_start(); @@ -1023,7 +1022,7 @@ static void out_net_info(const char *name, struct ebpf_net_event *evt) out_comma(); out_int("network_namespace", net->netns); - switch (evt->hdr.type) { + switch (hdr->type) { case EBPF_EVENT_NETWORK_CONNECTION_CLOSED: out_comma(); out_uint("bytes_sent", net->tcp.close.bytes_sent); @@ -1045,7 +1044,7 @@ static void out_network_event(const char *name, struct ebpf_net_event *evt) out_pid_info("pids", &evt->pids); out_comma(); - out_net_info("net", evt); + out_net_info("net", &evt->net, &evt->hdr); out_comma(); out_string("comm", (const char *)&evt->comm); @@ -1061,17 +1060,36 @@ static void out_network_connection_accepted_event(struct ebpf_net_event *evt) static void out_network_dns_event(struct ebpf_dns_event *event) { + out_object_start(); + out_event_type("DNS_EVENT"); + out_comma(); + + out_pid_info("pids", &event->pids); + out_comma(); + + out_net_info("net", &event->net, &event->hdr); + out_comma(); + + out_string("comm", (const char *)&event->comm); + + printf("\"data\":"); + out_array_start(); struct ebpf_varlen_field *field; FOR_EACH_VARLEN_FIELD(event->vl_fields, field) { - // TODO: format as JSON, or just remove? printf("packet %d: ", event->udp_evt); for (size_t i = 0; i < field->size; i++) { uint8_t part = field->data[i]; printf("%02X ", part); + if (i < field->size - 1) { + printf(", "); + } } - printf("\n"); } + out_array_end(); + + out_object_end(); + out_newline(); } static void out_network_connection_attempted_event(struct ebpf_net_event *evt) From ed64454f203899c0ff064dabac17910771a69e24 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 11 Sep 2024 13:26:10 -0700 Subject: [PATCH 21/47] further cleanup --- GPL/Events/Network/Network.h | 2 -- GPL/Events/Network/Probe.bpf.c | 10 ++++------ non-GPL/Events/Lib/EbpfEvents.c | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/GPL/Events/Network/Network.h b/GPL/Events/Network/Network.h index c584b6e9..bcb69f28 100644 --- a/GPL/Events/Network/Network.h +++ b/GPL/Events/Network/Network.h @@ -14,8 +14,6 @@ #define AF_INET 2 #define AF_INET6 10 -#define MSG_PEEK 2 - static int ebpf_sock_info__fill(struct ebpf_net_info *net, struct sock *sk) { int err = 0; diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 3b849a90..30a338ba 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -48,11 +48,11 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) { if (ebpf_events_is_trusted_pid()) - return 0; + goto out; struct ebpf_dns_event *event = get_event_buffer(); if (!event) - return 0; + goto out; // read from skbuf unsigned char *skb_head = BPF_CORE_READ(skb, head); @@ -127,8 +127,6 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) event->udp_evt = evt_type; ebpf_ringbuf_write(&ringbuf, event, EVENT_SIZE(event), 0); - return 0; - out: return 0; } @@ -140,7 +138,7 @@ int BPF_PROG(fentry__ip_send_skb, struct net *net, struct sk_buff *skb) } SEC("fentry/skb_consume_udp") -int BPF_PROG(fexit__skb_consume_udp, struct sock *sk, struct sk_buff *skb, int len) +int BPF_PROG(fentry__skb_consume_udp, struct sock *sk, struct sk_buff *skb, int len) { // skip peek operations if (len < 0) { @@ -156,7 +154,7 @@ int BPF_KPROBE(kprobe__ip_send_udp, struct net *net, struct sk_buff *skb) } SEC("kprobe/skb_consume_udp") -int BPF_KPROBE(kprobe__skb_consume_udp, struct net *net, struct sk_buff *skb) +int BPF_KPROBE(kprobe__skb_consume_udp, struct net *net, struct sk_buff *skb, int len) { return udp_skb_handle(skb, EBPF_NETWORK_EVENT_SKB_CONSUME_UDP); } diff --git a/non-GPL/Events/Lib/EbpfEvents.c b/non-GPL/Events/Lib/EbpfEvents.c index 13955de8..a0129db9 100644 --- a/non-GPL/Events/Lib/EbpfEvents.c +++ b/non-GPL/Events/Lib/EbpfEvents.c @@ -406,7 +406,7 @@ static inline int probe_set_autoload(struct btf *btf, struct EventProbe_bpf *obj 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__ip_send_skb, false); - err = err ?: bpf_program__set_autoload(obj->progs.fexit__skb_consume_udp, false); + err = err ?: bpf_program__set_autoload(obj->progs.fentry__skb_consume_udp, false); } return err; From 6baa2a1c7f66659b4f6bc4ddc4a116b9d4f5245e Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Thu, 12 Sep 2024 09:07:03 -0700 Subject: [PATCH 22/47] cleanup --- GPL/Events/EbpfEventProto.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index eb401124..d048474a 100644 --- a/GPL/Events/EbpfEventProto.h +++ b/GPL/Events/EbpfEventProto.h @@ -46,7 +46,7 @@ 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_DNS_PKT = (1 << 22), + EBPF_EVENT_NETWORK_DNS_PKT = (1 << 20), }; struct ebpf_event_header { @@ -393,11 +393,6 @@ struct ebpf_net_event { char comm[TASK_COMM_LEN]; } __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; @@ -406,7 +401,6 @@ struct ebpf_dns_event { enum ebpf_net_udp_info udp_evt; // Variable length fields: dns body struct ebpf_varlen_fields_start vl_fields; - // uint8_t pkt[MAX_DNS_PACKET]; } __attribute__((packed)); // Basic event statistics From 2a263af1ad365077b4aa9aa4200bc5c7d27c2f7c Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Thu, 12 Sep 2024 09:12:28 -0700 Subject: [PATCH 23/47] skip peeked calls in kprobe --- GPL/Events/Network/Probe.bpf.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 30a338ba..070172c0 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -156,6 +156,10 @@ int BPF_KPROBE(kprobe__ip_send_udp, struct net *net, struct sk_buff *skb) SEC("kprobe/skb_consume_udp") int BPF_KPROBE(kprobe__skb_consume_udp, struct net *net, struct sk_buff *skb, int len) { + // skip peek operations + if (len < 0) { + return 0; + } return udp_skb_handle(skb, EBPF_NETWORK_EVENT_SKB_CONSUME_UDP); } From 251154ecf6ff5d39018e2580bc1b7327b3c232ea Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Thu, 12 Sep 2024 11:26:46 -0700 Subject: [PATCH 24/47] change DNS max packet size --- GPL/Events/EbpfEventProto.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index d048474a..5ad5e934 100644 --- a/GPL/Events/EbpfEventProto.h +++ b/GPL/Events/EbpfEventProto.h @@ -11,12 +11,10 @@ #define EBPF_EVENTPROBE_EBPFEVENTPROTO_H #define TASK_COMM_LEN 16 -// The theoretical max size of DNS packets over UDP +// The theoretical max size of DNS packets over UDP is 512. // Like so many things in DNS this number probaby isn't 100% accurate. -// DNS extensions in RFC2671 and RFC6891 mean the actual size can be larger, -// although an additonal body over 512 is probably due to additional RR fields, -// which we can (probably) get away with throwing out for now. -#define MAX_DNS_PACKET 512 +// DNS extensions in RFC2671 and RFC6891 mean the actual size can be larger. +#define MAX_DNS_PACKET 1500 #ifndef __KERNEL__ #include From e59b322d9e24ecc5e1eeb4614c0f300ccd9e6a8d Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Mon, 16 Sep 2024 09:34:40 -0700 Subject: [PATCH 25/47] add counter for headlen==0 events --- GPL/Events/Network/Probe.bpf.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 070172c0..091117c2 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -51,7 +51,7 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) goto out; struct ebpf_dns_event *event = get_event_buffer(); - if (!event) + if (event == NULL) goto out; // read from skbuf @@ -107,6 +107,17 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) size_t readsize = BPF_CORE_READ(skb, len); size_t datalen = BPF_CORE_READ(skb, data_len); size_t headlen = readsize - datalen; + // headlen of zero indicates we have no non-paged data, and thus cannot read + // anything from the root data node + if (headlen == 0) { + u32 zero = 0; + struct ebpf_event_stats *es = bpf_map_lookup_elem(&ringbuf_stats, &zero); + if (es != NULL) { + es->lost++; + } + goto out; + } + if (headlen > MAX_DNS_PACKET) { headlen = MAX_DNS_PACKET; } From 520c8d4b9cf31b8a38912fc0d2c32145bf63f529 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Tue, 17 Sep 2024 08:01:48 -0700 Subject: [PATCH 26/47] cleanup, error handling --- GPL/Events/EbpfEventProto.h | 1 + GPL/Events/Network/Probe.bpf.c | 36 +++++++++++++++++++----- non-GPL/Events/EventsTrace/EventsTrace.c | 2 +- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index 5ad5e934..ae9cb88a 100644 --- a/GPL/Events/EbpfEventProto.h +++ b/GPL/Events/EbpfEventProto.h @@ -397,6 +397,7 @@ struct ebpf_dns_event { struct ebpf_net_info net; char comm[TASK_COMM_LEN]; enum ebpf_net_udp_info udp_evt; + uint64_t original_len; // Variable length fields: dns body struct ebpf_varlen_fields_start vl_fields; } __attribute__((packed)); diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 091117c2..47dcc350 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -67,8 +67,13 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) if (ip_hdr.version == 4) { proto = ip_hdr.protocol; - bpf_probe_read(event->net.saddr, 4, &ip_hdr.saddr); - bpf_probe_read(event->net.daddr, 4, &ip_hdr.daddr); + if (bpf_probe_read(event->net.saddr, 4, &ip_hdr.saddr) != 0) { + goto out; + }; + + if (bpf_probe_read(event->net.daddr, 4, &ip_hdr.daddr) != 0) { + goto out; + } event->net.family = EBPF_NETWORK_EVENT_AF_INET; } else if (ip_hdr.version == 6) { @@ -76,10 +81,17 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) 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); + if (bpf_probe_read(event->net.saddr6, 16, ip6_hdr.saddr.in6_u.u6_addr8) != 0) { + goto out; + } + + if (bpf_probe_read(event->net.daddr6, 16, ip6_hdr.daddr.in6_u.u6_addr8) != 0) { + goto out; + } event->net.family = EBPF_NETWORK_EVENT_AF_INET6; + } else { + goto out; } if (proto != IPPROTO_UDP) { @@ -87,9 +99,18 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) } struct udphdr udp_hdr; - 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); + if (bpf_core_read(&udp_hdr, sizeof(struct udphdr), skb_head + transport_header_offset) != 0) { + goto out; + } + + uint16_t dport = bpf_ntohs(udp_hdr.dest); + uint16_t sport = bpf_ntohs(udp_hdr.source); + if (sport != 53 && dport != 53) { + goto out; + } + + event->net.dport = dport; + event->net.sport = sport; event->net.transport = EBPF_NETWORK_EVENT_TRANSPORT_UDP; // filter out non-dns packets @@ -118,6 +139,7 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) goto out; } + event->original_len = headlen; if (headlen > MAX_DNS_PACKET) { headlen = MAX_DNS_PACKET; } diff --git a/non-GPL/Events/EventsTrace/EventsTrace.c b/non-GPL/Events/EventsTrace/EventsTrace.c index edd6a753..e03c0c6c 100644 --- a/non-GPL/Events/EventsTrace/EventsTrace.c +++ b/non-GPL/Events/EventsTrace/EventsTrace.c @@ -1080,7 +1080,7 @@ static void out_network_dns_event(struct ebpf_dns_event *event) printf("packet %d: ", event->udp_evt); for (size_t i = 0; i < field->size; i++) { uint8_t part = field->data[i]; - printf("%02X ", part); + printf("%02X", part); if (i < field->size - 1) { printf(", "); } From 7ea1643cceb0e521087ed7bb44844582ae25060b Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Tue, 17 Sep 2024 09:59:00 -0700 Subject: [PATCH 27/47] add new counter for sk_buff failures --- GPL/Events/EbpfEventProto.h | 1 + GPL/Events/Network/Probe.bpf.c | 2 +- non-GPL/Events/Lib/EbpfEvents.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index ae9cb88a..7cbf9e81 100644 --- a/GPL/Events/EbpfEventProto.h +++ b/GPL/Events/EbpfEventProto.h @@ -406,6 +406,7 @@ struct ebpf_dns_event { struct ebpf_event_stats { uint64_t lost; // lost events due to a full ringbuffer uint64_t sent; // events sent through the ringbuffer + uint64_t paged_out; // indicates that that a given sk_buff event contained no non-paged data }; #endif // EBPF_EVENTPROBE_EBPFEVENTPROTO_H diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 47dcc350..ac8a6642 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -134,7 +134,7 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) u32 zero = 0; struct ebpf_event_stats *es = bpf_map_lookup_elem(&ringbuf_stats, &zero); if (es != NULL) { - es->lost++; + es->paged_out++; } goto out; } diff --git a/non-GPL/Events/Lib/EbpfEvents.c b/non-GPL/Events/Lib/EbpfEvents.c index a0129db9..87f3181e 100644 --- a/non-GPL/Events/Lib/EbpfEvents.c +++ b/non-GPL/Events/Lib/EbpfEvents.c @@ -820,6 +820,7 @@ int ebpf_event_ctx__read_stats(struct ebpf_event_ctx *ctx, struct ebpf_event_sta for (i = 0; i < libbpf_num_possible_cpus(); i++) { ees->lost += pcpu_ees[i].lost; ees->sent += pcpu_ees[i].sent; + ees->paged_out += pcpu_ees[i].paged_out; } return 0; From 72b356c4e4993216bca02c8ecabb0c41f593e625 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Tue, 17 Sep 2024 10:09:46 -0700 Subject: [PATCH 28/47] format.. --- GPL/Events/EbpfEventProto.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index 7cbf9e81..bb51b1c9 100644 --- a/GPL/Events/EbpfEventProto.h +++ b/GPL/Events/EbpfEventProto.h @@ -404,8 +404,8 @@ struct ebpf_dns_event { // Basic event statistics struct ebpf_event_stats { - uint64_t lost; // lost events due to a full ringbuffer - uint64_t sent; // events sent through the ringbuffer + uint64_t lost; // lost events due to a full ringbuffer + uint64_t sent; // events sent through the ringbuffer uint64_t paged_out; // indicates that that a given sk_buff event contained no non-paged data }; From 43f126aeb8453c43d5348f6c2da0344dbe04ea16 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Tue, 17 Sep 2024 10:20:10 -0700 Subject: [PATCH 29/47] update name --- GPL/Events/EbpfEventProto.h | 7 ++++--- GPL/Events/Network/Probe.bpf.c | 2 +- non-GPL/Events/Lib/EbpfEvents.c | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index bb51b1c9..3def56ae 100644 --- a/GPL/Events/EbpfEventProto.h +++ b/GPL/Events/EbpfEventProto.h @@ -404,9 +404,10 @@ struct ebpf_dns_event { // Basic event statistics struct ebpf_event_stats { - uint64_t lost; // lost events due to a full ringbuffer - uint64_t sent; // events sent through the ringbuffer - uint64_t paged_out; // indicates that that a given sk_buff event contained no non-paged data + uint64_t lost; // lost events due to a full ringbuffer + uint64_t sent; // events sent through the ringbuffer + uint64_t + dns_body_paged_out; // indicates that an sk_buff for a DNS event contained no non-paged data }; #endif // EBPF_EVENTPROBE_EBPFEVENTPROTO_H diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index ac8a6642..65ca84a5 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -134,7 +134,7 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) u32 zero = 0; struct ebpf_event_stats *es = bpf_map_lookup_elem(&ringbuf_stats, &zero); if (es != NULL) { - es->paged_out++; + es->dns_body_paged_out++; } goto out; } diff --git a/non-GPL/Events/Lib/EbpfEvents.c b/non-GPL/Events/Lib/EbpfEvents.c index 87f3181e..4b93f06f 100644 --- a/non-GPL/Events/Lib/EbpfEvents.c +++ b/non-GPL/Events/Lib/EbpfEvents.c @@ -820,7 +820,7 @@ int ebpf_event_ctx__read_stats(struct ebpf_event_ctx *ctx, struct ebpf_event_sta for (i = 0; i < libbpf_num_possible_cpus(); i++) { ees->lost += pcpu_ees[i].lost; ees->sent += pcpu_ees[i].sent; - ees->paged_out += pcpu_ees[i].paged_out; + ees->dns_body_paged_out += pcpu_ees[i].dns_body_paged_out; } return 0; From 55f89afe1a93e15f90e4311295615255537a37bf Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Tue, 17 Sep 2024 11:53:34 -0700 Subject: [PATCH 30/47] update docs, var name --- GPL/Events/EbpfEventProto.h | 4 ++-- GPL/Events/Network/Probe.bpf.c | 2 +- non-GPL/Events/Lib/EbpfEvents.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index 3def56ae..1ee8235f 100644 --- a/GPL/Events/EbpfEventProto.h +++ b/GPL/Events/EbpfEventProto.h @@ -406,8 +406,8 @@ struct ebpf_dns_event { struct ebpf_event_stats { uint64_t lost; // lost events due to a full ringbuffer uint64_t sent; // events sent through the ringbuffer - uint64_t - dns_body_paged_out; // indicates that an sk_buff for a DNS event contained no non-paged data + // indicates that an sk_buff for a DNS event contained no non-paged data in sk_buff->data + uint64_t dns_zero_body; }; #endif // EBPF_EVENTPROBE_EBPFEVENTPROTO_H diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 65ca84a5..75720de5 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -134,7 +134,7 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) u32 zero = 0; struct ebpf_event_stats *es = bpf_map_lookup_elem(&ringbuf_stats, &zero); if (es != NULL) { - es->dns_body_paged_out++; + es->dns_zero_body++; } goto out; } diff --git a/non-GPL/Events/Lib/EbpfEvents.c b/non-GPL/Events/Lib/EbpfEvents.c index 4b93f06f..c48c1fe4 100644 --- a/non-GPL/Events/Lib/EbpfEvents.c +++ b/non-GPL/Events/Lib/EbpfEvents.c @@ -820,7 +820,7 @@ int ebpf_event_ctx__read_stats(struct ebpf_event_ctx *ctx, struct ebpf_event_sta for (i = 0; i < libbpf_num_possible_cpus(); i++) { ees->lost += pcpu_ees[i].lost; ees->sent += pcpu_ees[i].sent; - ees->dns_body_paged_out += pcpu_ees[i].dns_body_paged_out; + ees->dns_zero_body += pcpu_ees[i].dns_zero_body; } return 0; From 49e1ea1bc7f47fe56f4c56fbd2d796e8c85ef72f Mon Sep 17 00:00:00 2001 From: Christiano Haesbaert Date: Tue, 17 Sep 2024 20:55:43 +0200 Subject: [PATCH 31/47] tiny rewording --- GPL/Events/EbpfEventProto.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/GPL/Events/EbpfEventProto.h b/GPL/Events/EbpfEventProto.h index 1ee8235f..0277d72f 100644 --- a/GPL/Events/EbpfEventProto.h +++ b/GPL/Events/EbpfEventProto.h @@ -404,10 +404,9 @@ struct ebpf_dns_event { // Basic event statistics struct ebpf_event_stats { - uint64_t lost; // lost events due to a full ringbuffer - uint64_t sent; // events sent through the ringbuffer - // indicates that an sk_buff for a DNS event contained no non-paged data in sk_buff->data - uint64_t dns_zero_body; + uint64_t lost; // lost events due to a full ringbuffer + uint64_t sent; // events sent through the ringbuffer + uint64_t dns_zero_body; // indicates that the dns body of a sk_buff was unavailable }; #endif // EBPF_EVENTPROBE_EBPFEVENTPROTO_H From 274ac5a502341cddff87bd511947d46d9137a010 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 18 Sep 2024 07:55:15 -0700 Subject: [PATCH 32/47] add tests, clean up json --- non-GPL/Events/EventsTrace/EventsTrace.c | 4 ++-- testing/testrunner/main.go | 5 ++--- testing/testrunner/tests.go | 24 ++++++++++++++++++++++++ testing/testrunner/utils.go | 18 ++++++++++++++++++ 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/non-GPL/Events/EventsTrace/EventsTrace.c b/non-GPL/Events/EventsTrace/EventsTrace.c index e03c0c6c..ac07548f 100644 --- a/non-GPL/Events/EventsTrace/EventsTrace.c +++ b/non-GPL/Events/EventsTrace/EventsTrace.c @@ -1071,16 +1071,16 @@ static void out_network_dns_event(struct ebpf_dns_event *event) out_comma(); out_string("comm", (const char *)&event->comm); + out_comma(); printf("\"data\":"); out_array_start(); struct ebpf_varlen_field *field; FOR_EACH_VARLEN_FIELD(event->vl_fields, field) { - printf("packet %d: ", event->udp_evt); for (size_t i = 0; i < field->size; i++) { uint8_t part = field->data[i]; - printf("%02X", part); + printf("%d", part); if (i < field->size - 1) { printf(", "); } diff --git a/testing/testrunner/main.go b/testing/testrunner/main.go index f0c13232..e73781f1 100644 --- a/testing/testrunner/main.go +++ b/testing/testrunner/main.go @@ -9,9 +9,7 @@ package main -import ( - "fmt" -) +import "fmt" func main() { RunEventsTest(TestFeaturesCorrect) @@ -32,6 +30,7 @@ func main() { RunEventsTest(TestTcpv6ConnectionAttempt, "--net-conn-attempt") RunEventsTest(TestTcpv6ConnectionAccept, "--net-conn-accept") RunEventsTest(TestTcpv6ConnectionClose, "--net-conn-close") + RunEventsTest(TestDNSMonitor, "--net-conn-dns-pkt") RunTest(TestTcFilter) diff --git a/testing/testrunner/tests.go b/testing/testrunner/tests.go index a8a45710..2e932966 100644 --- a/testing/testrunner/tests.go +++ b/testing/testrunner/tests.go @@ -152,6 +152,30 @@ func TestForkExec(et *EventsTraceInstance) { AssertStringsEqual(execEvent.Cwd, "/") } +func TestDNSMonitor(et *EventsTraceInstance) { + runTestCmd("dig github.com") + + type dnsOutput struct { + Data []uint8 `json:"data"` + NetConnAcceptEvent + } + + line := et.GetNextEventJson("DNS_EVENT") + lineData := dnsOutput{} + err := json.Unmarshal([]byte(line), &lineData) + if err != nil { + TestFail("failed to unmarshal JSON body", err) + } + + AssertStringsEqual(lineData.Net.Transport, "UDP") + AssertStringsEqual(lineData.Net.Family, "AF_INET") + // first two bytes of a DNS body will be the session ID for the query, and + // should not be zero + AssertNotZero(lineData.Data[0]) + AssertNotZero(lineData.Data[1]) + +} + func TestFileCreate(et *EventsTraceInstance) { outputStr := runTestBin("create_rename_delete_file") var binOutput struct { diff --git a/testing/testrunner/utils.go b/testing/testrunner/utils.go index 50880e55..6140dcae 100644 --- a/testing/testrunner/utils.go +++ b/testing/testrunner/utils.go @@ -193,10 +193,21 @@ func getJsonEventType(jsonLine string) (string, error) { return jsonUnmarshaled.EventType, nil } +func runTestCmd(cmdStr string) []byte { + cmdArg := strings.Split(cmdStr, " ") + cmd := exec.Command(cmdArg[0], cmdArg[1:]...) + return handleTestOutput(cmd) +} + func runTestBin(binName string) []byte { cmd := exec.Command(fmt.Sprintf("/%s", binName)) + return handleTestOutput(cmd) + +} +func handleTestOutput(cmd *exec.Cmd) []byte { output, err := cmd.Output() + binName := cmd.Path if err != nil { fmt.Printf("===== stderr of %s =====\n", binName) fmt.Println(err) @@ -238,6 +249,12 @@ func AssertStringsEqual(a, b string) { } } +func AssertNotZero(a uint8) { + if a == 0 { + TestFail(fmt.Sprintf("Test assertion failed %d == 0", a)) + } +} + func AssertInt64Equal(a, b int64) { if a != b { TestFail(fmt.Sprintf("Test assertion failed %d != %d", a, b)) @@ -345,6 +362,7 @@ func RunTest(f func()) { func RunEventsTest(f func(*EventsTraceInstance), args ...string) { testFuncName := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() ctx, cancel := context.WithTimeout(context.TODO(), 90*time.Second) + fmt.Printf("running test: %s\n", testFuncName) et := NewEventsTrace(ctx, args...) et.Start(ctx) From 28231f2a5e7ed3616fa7bd8dccfee86746bbef28 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 18 Sep 2024 08:04:21 -0700 Subject: [PATCH 33/47] use host command --- testing/testrunner/tests.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/testrunner/tests.go b/testing/testrunner/tests.go index 2e932966..231169c9 100644 --- a/testing/testrunner/tests.go +++ b/testing/testrunner/tests.go @@ -153,7 +153,7 @@ func TestForkExec(et *EventsTraceInstance) { } func TestDNSMonitor(et *EventsTraceInstance) { - runTestCmd("dig github.com") + runTestCmd("host github.com") type dnsOutput struct { Data []uint8 `json:"data"` From c25ae028f7b4731a59498ad7296d94e165de02f4 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 18 Sep 2024 08:11:17 -0700 Subject: [PATCH 34/47] use path.. --- testing/testrunner/tests.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/testrunner/tests.go b/testing/testrunner/tests.go index 231169c9..9453ee4c 100644 --- a/testing/testrunner/tests.go +++ b/testing/testrunner/tests.go @@ -153,7 +153,7 @@ func TestForkExec(et *EventsTraceInstance) { } func TestDNSMonitor(et *EventsTraceInstance) { - runTestCmd("host github.com") + runTestCmd("/usr/bin/host github.com") type dnsOutput struct { Data []uint8 `json:"data"` From 00bd9d968bd8514f464ebaa8b8012c9d6d0f6012 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 18 Sep 2024 08:19:35 -0700 Subject: [PATCH 35/47] use arg array --- testing/testrunner/tests.go | 2 +- testing/testrunner/utils.go | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/testing/testrunner/tests.go b/testing/testrunner/tests.go index 9453ee4c..e1965234 100644 --- a/testing/testrunner/tests.go +++ b/testing/testrunner/tests.go @@ -153,7 +153,7 @@ func TestForkExec(et *EventsTraceInstance) { } func TestDNSMonitor(et *EventsTraceInstance) { - runTestCmd("/usr/bin/host github.com") + runTestCmd([]string{"/usr/bin/host", "github.com"}) type dnsOutput struct { Data []uint8 `json:"data"` diff --git a/testing/testrunner/utils.go b/testing/testrunner/utils.go index 6140dcae..2eac3c11 100644 --- a/testing/testrunner/utils.go +++ b/testing/testrunner/utils.go @@ -193,8 +193,7 @@ func getJsonEventType(jsonLine string) (string, error) { return jsonUnmarshaled.EventType, nil } -func runTestCmd(cmdStr string) []byte { - cmdArg := strings.Split(cmdStr, " ") +func runTestCmd(cmdArg []string) []byte { cmd := exec.Command(cmdArg[0], cmdArg[1:]...) return handleTestOutput(cmd) } From 5b494d114db16d97aca0a1b643daf4df7655bfcd Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 18 Sep 2024 08:27:16 -0700 Subject: [PATCH 36/47] use bash for test --- testing/testrunner/tests.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/testrunner/tests.go b/testing/testrunner/tests.go index e1965234..ec792ca0 100644 --- a/testing/testrunner/tests.go +++ b/testing/testrunner/tests.go @@ -153,7 +153,7 @@ func TestForkExec(et *EventsTraceInstance) { } func TestDNSMonitor(et *EventsTraceInstance) { - runTestCmd([]string{"/usr/bin/host", "github.com"}) + runTestCmd([]string{"bash", "-c", "host github.com"}) type dnsOutput struct { Data []uint8 `json:"data"` From 88f021e15b43a010fcedea3d6e13956df10f278f Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 18 Sep 2024 08:27:56 -0700 Subject: [PATCH 37/47] use bash for test --- testing/testrunner/tests.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/testrunner/tests.go b/testing/testrunner/tests.go index ec792ca0..23800a97 100644 --- a/testing/testrunner/tests.go +++ b/testing/testrunner/tests.go @@ -153,7 +153,7 @@ func TestForkExec(et *EventsTraceInstance) { } func TestDNSMonitor(et *EventsTraceInstance) { - runTestCmd([]string{"bash", "-c", "host github.com"}) + runTestCmd([]string{"/usr/bin/bash", "-c", "host github.com"}) type dnsOutput struct { Data []uint8 `json:"data"` From 318f491797d81adbaf1698a9b9e151f4f36f19a3 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 18 Sep 2024 08:43:28 -0700 Subject: [PATCH 38/47] use sh --- testing/testrunner/tests.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/testrunner/tests.go b/testing/testrunner/tests.go index 23800a97..b76557e7 100644 --- a/testing/testrunner/tests.go +++ b/testing/testrunner/tests.go @@ -153,7 +153,7 @@ func TestForkExec(et *EventsTraceInstance) { } func TestDNSMonitor(et *EventsTraceInstance) { - runTestCmd([]string{"/usr/bin/bash", "-c", "host github.com"}) + runTestCmd([]string{"/usr/bin/sh", "-c", "host github.com"}) type dnsOutput struct { Data []uint8 `json:"data"` From 1f5559621f59dcfebd9d4c5860f7a0a95e2dd0e9 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 18 Sep 2024 09:40:18 -0700 Subject: [PATCH 39/47] test with a special binary... --- testing/test_bins/udp_send.c | 55 ++++++++++++++++++++++++++++++++++++ testing/testrunner/tests.go | 2 +- 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 testing/test_bins/udp_send.c diff --git a/testing/test_bins/udp_send.c b/testing/test_bins/udp_send.c new file mode 100644 index 00000000..96f2824a --- /dev/null +++ b/testing/test_bins/udp_send.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define BUFFER_SIZE 512 + +char buffer[BUFFER_SIZE]; + +void create_buffer(uint8_t* buffer, size_t length) +{ + for (size_t i = 0; i < length; i++) + { + buffer[i] = 0xff; + } +} + +int main(int argc, char **argv) +{ + int sockfd; + struct sockaddr_in server; + + create_buffer(buffer, sizeof(buffer)); + + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + fprintf(stderr, "Error opening socket"); + return -1; + } + + bzero((char*)&server, sizeof(server)); + server.sin_family = AF_INET; + server.sin_addr.s_addr = inet_addr("127.0.0.1"); + server.sin_port = htons(53); + printf("sending...\n"); + if (sendto(sockfd, &buffer, BUFFER_SIZE, 0,(const struct sockaddr*)&server, sizeof(server)) < 0) + { + fprintf(stderr, "Error in sendto()\n"); + return -1; + } + + + return 0; +} \ No newline at end of file diff --git a/testing/testrunner/tests.go b/testing/testrunner/tests.go index b76557e7..e254d8a3 100644 --- a/testing/testrunner/tests.go +++ b/testing/testrunner/tests.go @@ -153,7 +153,7 @@ func TestForkExec(et *EventsTraceInstance) { } func TestDNSMonitor(et *EventsTraceInstance) { - runTestCmd([]string{"/usr/bin/sh", "-c", "host github.com"}) + runTestBin("udp_send") type dnsOutput struct { Data []uint8 `json:"data"` From d14986756c467bcba6c9dcccfaddad535290d33a Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 18 Sep 2024 09:42:36 -0700 Subject: [PATCH 40/47] format --- testing/test_bins/udp_send.c | 41 ++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/testing/test_bins/udp_send.c b/testing/test_bins/udp_send.c index 96f2824a..a72198b0 100644 --- a/testing/test_bins/udp_send.c +++ b/testing/test_bins/udp_send.c @@ -1,25 +1,23 @@ +#include +#include +#include +#include +#include #include #include -#include #include -#include -#include #include -#include -#include #include -#include -#include - +#include +#include #define BUFFER_SIZE 512 char buffer[BUFFER_SIZE]; -void create_buffer(uint8_t* buffer, size_t length) +void create_buffer(uint8_t *buffer, size_t length) { - for (size_t i = 0; i < length; i++) - { + for (size_t i = 0; i < length; i++) { buffer[i] = 0xff; } } @@ -31,25 +29,22 @@ int main(int argc, char **argv) create_buffer(buffer, sizeof(buffer)); - sockfd = socket(AF_INET, SOCK_DGRAM, 0); - if (sockfd < 0) - { + if (sockfd < 0) { fprintf(stderr, "Error opening socket"); return -1; } - bzero((char*)&server, sizeof(server)); - server.sin_family = AF_INET; + bzero((char *)&server, sizeof(server)); + server.sin_family = AF_INET; server.sin_addr.s_addr = inet_addr("127.0.0.1"); - server.sin_port = htons(53); + server.sin_port = htons(53); printf("sending...\n"); - if (sendto(sockfd, &buffer, BUFFER_SIZE, 0,(const struct sockaddr*)&server, sizeof(server)) < 0) - { - fprintf(stderr, "Error in sendto()\n"); - return -1; - } - + if (sendto(sockfd, &buffer, BUFFER_SIZE, 0, (const struct sockaddr *)&server, sizeof(server)) < + 0) { + fprintf(stderr, "Error in sendto()\n"); + return -1; + } return 0; } \ No newline at end of file From b74eec94e2979df6145631201d7f7f7ba40dbfdd Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 18 Sep 2024 10:19:09 -0700 Subject: [PATCH 41/47] clean up --- GPL/Events/Network/Probe.bpf.c | 10 ++++------ testing/test_bins/udp_send.c | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 75720de5..90c54537 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -46,6 +46,9 @@ static int inet_csk_accept__exit(struct sock *sk) static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) { + if (skb == NULL){ + goto out; + } if (ebpf_events_is_trusted_pid()) goto out; @@ -105,6 +108,7 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) uint16_t dport = bpf_ntohs(udp_hdr.dest); uint16_t sport = bpf_ntohs(udp_hdr.source); + // filter out non-DNS packets if (sport != 53 && dport != 53) { goto out; } @@ -113,11 +117,6 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) event->net.sport = sport; event->net.transport = EBPF_NETWORK_EVENT_TRANSPORT_UDP; - // filter out non-dns packets - if (event->net.sport != 53 && event->net.dport != 53) { - 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); @@ -147,7 +146,6 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) ebpf_vl_fields__init(&event->vl_fields); struct ebpf_varlen_field *field; field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_DNS_BODY); - long ret = bpf_probe_read_kernel(field->data, headlen, skb_head + transport_header_offset + sizeof(struct udphdr)); if (ret != 0) { diff --git a/testing/test_bins/udp_send.c b/testing/test_bins/udp_send.c index a72198b0..47360ce8 100644 --- a/testing/test_bins/udp_send.c +++ b/testing/test_bins/udp_send.c @@ -27,7 +27,7 @@ int main(int argc, char **argv) int sockfd; struct sockaddr_in server; - create_buffer(buffer, sizeof(buffer)); + memset(&buffer, 0xff, sizeof(buffer)); sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { From fbe2a42fa5c0fcd5537aa5a3599b853009e415f4 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 18 Sep 2024 10:27:02 -0700 Subject: [PATCH 42/47] format... --- GPL/Events/Network/Probe.bpf.c | 4 ++-- testing/test_bins/udp_send.c | 7 ------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index 90c54537..b2efbd47 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -46,7 +46,7 @@ static int inet_csk_accept__exit(struct sock *sk) static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) { - if (skb == NULL){ + if (skb == NULL) { goto out; } @@ -145,7 +145,7 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) ebpf_vl_fields__init(&event->vl_fields); struct ebpf_varlen_field *field; - field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_DNS_BODY); + field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_DNS_BODY); long ret = bpf_probe_read_kernel(field->data, headlen, skb_head + transport_header_offset + sizeof(struct udphdr)); if (ret != 0) { diff --git a/testing/test_bins/udp_send.c b/testing/test_bins/udp_send.c index 47360ce8..e3a5f06c 100644 --- a/testing/test_bins/udp_send.c +++ b/testing/test_bins/udp_send.c @@ -15,13 +15,6 @@ char buffer[BUFFER_SIZE]; -void create_buffer(uint8_t *buffer, size_t length) -{ - for (size_t i = 0; i < length; i++) { - buffer[i] = 0xff; - } -} - int main(int argc, char **argv) { int sockfd; From 08648ca303ff1654175abf69d89e5119117dd858 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 18 Sep 2024 11:17:18 -0700 Subject: [PATCH 43/47] set correct read len for outgoing packets --- GPL/Events/Network/Probe.bpf.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/GPL/Events/Network/Probe.bpf.c b/GPL/Events/Network/Probe.bpf.c index b2efbd47..dedb11af 100644 --- a/GPL/Events/Network/Probe.bpf.c +++ b/GPL/Events/Network/Probe.bpf.c @@ -62,8 +62,8 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) // get lengths u16 net_header_offset = BPF_CORE_READ(skb, network_header); u16 transport_header_offset = BPF_CORE_READ(skb, transport_header); - - u8 proto = 0; + size_t network_header_size = 0; + u8 proto = 0; struct iphdr ip_hdr; bpf_core_read(&ip_hdr, sizeof(struct iphdr), skb_head + net_header_offset); @@ -77,8 +77,8 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) if (bpf_probe_read(event->net.daddr, 4, &ip_hdr.daddr) != 0) { goto out; } - - event->net.family = EBPF_NETWORK_EVENT_AF_INET; + network_header_size = sizeof(struct iphdr); + 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), skb_head + net_header_offset); @@ -92,7 +92,8 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) goto out; } - event->net.family = EBPF_NETWORK_EVENT_AF_INET6; + network_header_size = sizeof(struct ipv6hdr); + event->net.family = EBPF_NETWORK_EVENT_AF_INET6; } else { goto out; } @@ -138,21 +139,29 @@ static int udp_skb_handle(struct sk_buff *skb, enum ebpf_net_udp_info evt_type) goto out; } + size_t body_size = headlen; + // for ip_send_skb(), we're at a point in the network stack where we've just prepended the IP + // header, so the normal headlen for the skb_buff includes the headers. Reset them so we *just* + // read the application body. + if (evt_type == EBPF_NETWORK_EVENT_IP_SEND_UDP) { + body_size = headlen - (sizeof(struct udphdr) + network_header_size); + } + event->original_len = headlen; - if (headlen > MAX_DNS_PACKET) { - headlen = MAX_DNS_PACKET; + if (body_size > MAX_DNS_PACKET) { + body_size = MAX_DNS_PACKET; } ebpf_vl_fields__init(&event->vl_fields); struct ebpf_varlen_field *field; field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_DNS_BODY); - long ret = bpf_probe_read_kernel(field->data, headlen, + long ret = bpf_probe_read_kernel(field->data, body_size, skb_head + transport_header_offset + sizeof(struct udphdr)); if (ret != 0) { bpf_printk("error reading in data buffer: %d", ret); goto out; } - ebpf_vl_field__set_size(&event->vl_fields, field, headlen); + ebpf_vl_field__set_size(&event->vl_fields, field, body_size); event->hdr.type = EBPF_EVENT_NETWORK_DNS_PKT; event->udp_evt = evt_type; From 5c027da920a4124ac443df6801d98cf6ceb79127 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Wed, 18 Sep 2024 15:43:38 -0700 Subject: [PATCH 44/47] revert changes to utils --- testing/testrunner/utils.go | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/testing/testrunner/utils.go b/testing/testrunner/utils.go index 2eac3c11..345d04b1 100644 --- a/testing/testrunner/utils.go +++ b/testing/testrunner/utils.go @@ -193,20 +193,10 @@ func getJsonEventType(jsonLine string) (string, error) { return jsonUnmarshaled.EventType, nil } -func runTestCmd(cmdArg []string) []byte { - cmd := exec.Command(cmdArg[0], cmdArg[1:]...) - return handleTestOutput(cmd) -} - func runTestBin(binName string) []byte { cmd := exec.Command(fmt.Sprintf("/%s", binName)) - return handleTestOutput(cmd) - -} -func handleTestOutput(cmd *exec.Cmd) []byte { output, err := cmd.Output() - binName := cmd.Path if err != nil { fmt.Printf("===== stderr of %s =====\n", binName) fmt.Println(err) @@ -230,6 +220,12 @@ func AssertPidInfoEqual(tpi TestPidInfo, pi PidInfo) { AssertInt64Equal(pi.Sid, tpi.Sid) } +func AssertNotZero(a uint8) { + if a == 0 { + TestFail(fmt.Sprintf("Test assertion failed %d == 0", a)) + } +} + func AssertTrue(val bool) { if !val { TestFail(fmt.Sprintf("Expected %t to be true", val)) @@ -248,12 +244,6 @@ func AssertStringsEqual(a, b string) { } } -func AssertNotZero(a uint8) { - if a == 0 { - TestFail(fmt.Sprintf("Test assertion failed %d == 0", a)) - } -} - func AssertInt64Equal(a, b int64) { if a != b { TestFail(fmt.Sprintf("Test assertion failed %d != %d", a, b)) @@ -361,7 +351,6 @@ func RunTest(f func()) { func RunEventsTest(f func(*EventsTraceInstance), args ...string) { testFuncName := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() ctx, cancel := context.WithTimeout(context.TODO(), 90*time.Second) - fmt.Printf("running test: %s\n", testFuncName) et := NewEventsTrace(ctx, args...) et.Start(ctx) From d38841f106d18d7500914e712d08dad9b6f1d2ea Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Thu, 19 Sep 2024 07:30:47 -0700 Subject: [PATCH 45/47] use better udp send --- testing/test_bins/udp_send.c | 75 +++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/testing/test_bins/udp_send.c b/testing/test_bins/udp_send.c index e3a5f06c..b3ff59ce 100644 --- a/testing/test_bins/udp_send.c +++ b/testing/test_bins/udp_send.c @@ -1,43 +1,48 @@ -#include -#include -#include +#define _GNU_SOURCE /* program_invocation_name */ +#include +#include + #include -#include + +#include + +#include #include #include #include -#include -#include -#include -#include +#include +#include -#define BUFFER_SIZE 512 +int +main(int argc, char *argv[]) +{ + struct sockaddr_in sin; + int sock, ch, do_connect; + ssize_t n; + char* inaddr = "127.0.0.1"; + uint64_t buf[] = { + 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, + 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef + }; -char buffer[BUFFER_SIZE]; + bzero(&sin, sizeof(sin)); -int main(int argc, char **argv) -{ - int sockfd; - struct sockaddr_in server; - - memset(&buffer, 0xff, sizeof(buffer)); - - sockfd = socket(AF_INET, SOCK_DGRAM, 0); - if (sockfd < 0) { - fprintf(stderr, "Error opening socket"); - return -1; - } - - bzero((char *)&server, sizeof(server)); - server.sin_family = AF_INET; - server.sin_addr.s_addr = inet_addr("127.0.0.1"); - server.sin_port = htons(53); - printf("sending...\n"); - if (sendto(sockfd, &buffer, BUFFER_SIZE, 0, (const struct sockaddr *)&server, sizeof(server)) < - 0) { - fprintf(stderr, "Error in sendto()\n"); - return -1; - } - - return 0; + + if (inet_aton(inaddr, &sin.sin_addr) == 0) + errx(1, "inet_aton(%s)", inaddr); + sin.sin_port = htons(53); + sin.sin_family = AF_INET; + + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + err(1, "socket"); + + + n = sendto(sock, buf, sizeof(buf), 0, + (struct sockaddr *)&sin, sizeof(sin)); + if (n == -1) + err(1, "sendto"); + else if (n != sizeof(buf)) + errx(1, "sendto: shortcount"); + + return (0); } \ No newline at end of file From 802fa43304abfc9b9f4238ccf7e2bdd19b7fc182 Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Thu, 19 Sep 2024 07:35:02 -0700 Subject: [PATCH 46/47] format --- testing/test_bins/udp_send.c | 66 ++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/testing/test_bins/udp_send.c b/testing/test_bins/udp_send.c index b3ff59ce..450c08b3 100644 --- a/testing/test_bins/udp_send.c +++ b/testing/test_bins/udp_send.c @@ -1,48 +1,42 @@ -#define _GNU_SOURCE /* program_invocation_name */ -#include +#define _GNU_SOURCE /* program_invocation_name */ #include +#include #include #include -#include +#include +#include #include #include #include -#include -#include +#include -int -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { - struct sockaddr_in sin; - int sock, ch, do_connect; - ssize_t n; - char* inaddr = "127.0.0.1"; - uint64_t buf[] = { - 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, - 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef - }; - - bzero(&sin, sizeof(sin)); - - - if (inet_aton(inaddr, &sin.sin_addr) == 0) - errx(1, "inet_aton(%s)", inaddr); - sin.sin_port = htons(53); - sin.sin_family = AF_INET; - - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) - err(1, "socket"); - - - n = sendto(sock, buf, sizeof(buf), 0, - (struct sockaddr *)&sin, sizeof(sin)); - if (n == -1) - err(1, "sendto"); - else if (n != sizeof(buf)) - errx(1, "sendto: shortcount"); - - return (0); + struct sockaddr_in sin; + int sock, ch, do_connect; + ssize_t n; + char *inaddr = "127.0.0.1"; + uint64_t buf[] = {0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, + 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef}; + + bzero(&sin, sizeof(sin)); + + if (inet_aton(inaddr, &sin.sin_addr) == 0) + errx(1, "inet_aton(%s)", inaddr); + sin.sin_port = htons(53); + sin.sin_family = AF_INET; + + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + err(1, "socket"); + + n = sendto(sock, buf, sizeof(buf), 0, (struct sockaddr *)&sin, sizeof(sin)); + if (n == -1) + err(1, "sendto"); + else if (n != sizeof(buf)) + errx(1, "sendto: shortcount"); + + return (0); } \ No newline at end of file From e827ae98f86026dba51c8b5431bc009d64c369bc Mon Sep 17 00:00:00 2001 From: fearful-symmetry Date: Thu, 19 Sep 2024 07:37:59 -0700 Subject: [PATCH 47/47] clean up --- testing/test_bins/udp_send.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/test_bins/udp_send.c b/testing/test_bins/udp_send.c index 450c08b3..04a99d20 100644 --- a/testing/test_bins/udp_send.c +++ b/testing/test_bins/udp_send.c @@ -16,7 +16,7 @@ int main(int argc, char *argv[]) { struct sockaddr_in sin; - int sock, ch, do_connect; + int sock; ssize_t n; char *inaddr = "127.0.0.1"; uint64_t buf[] = {0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,