Skip to content

Commit 06c7500

Browse files
committed
feat: use UDP instead of raw socket for XDP triggers
- implement UDP trigger packets - remove all raw socket code and CAP_NET_RAW requirement - update XDP program to parse UDP packets (127.0.0.1:9999 for now)
1 parent aa72511 commit 06c7500

File tree

3 files changed

+116
-108
lines changed

3 files changed

+116
-108
lines changed

capabilities.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
* CAP_SYS_ADMIN -> needed to change /proc/sys/kernel/kptr_restrict from 2 to 0 (not needed if set to 1 or 0), needed to access
1616
* /proc/iomem if CONFIG_KALLSYMS_ALL is not active and so iomem_resources is not available, needed on old kernels
1717
* CAP_DAC_OVERRIDE -> needed to create a brand new dump file in the case the directory is not owned by the user running LEMON
18-
* CAP_NET_RAW -> needed to create raw sockets for XDP
1918
*/
2019

2120

ebpf/mem.ebpf.c

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
11
#ifdef CORE
22
#include "../vmlinux.h"
33
#include <bpf/bpf_core_read.h>
4+
5+
#ifndef ETH_P_IP
6+
#define ETH_P_IP 0x0800
7+
#endif
8+
9+
#ifndef IPPROTO_UDP
10+
#define IPPROTO_UDP 17
11+
#endif
412
#else
13+
#include <asm/ptrace.h>
514
#include <linux/bpf.h>
615
#include <linux/if_ether.h>
7-
#include <asm/ptrace.h>
16+
#include <linux/in.h>
17+
#include <linux/ip.h>
18+
#include <linux/udp.h>
819
#endif
920

1021
#include <bpf/bpf_helpers.h>
1122
#include <bpf/bpf_tracing.h>
23+
#include <bpf/bpf_endian.h>
1224

1325
#include "../lemon.h"
1426

@@ -114,37 +126,77 @@ int read_kernel_memory_uprobe(struct pt_regs *ctx)
114126
return read_memory(address, dump_size);
115127
}
116128

129+
#define TRIGGER_PACKET_PORT 9999
130+
#define TRIGGER_PACKET_ADDR 0x7f000001 /* 127.0.0.1 */
131+
117132
/*
118133
* read_kernel_memory_xdp() - XDP program to trigger a kernel memory read
119134
* @ctx: Pointer to the XDP context containing packet metadata
120135
*
121-
* Parses a synthetic packet containing address and size parameters used to
122-
* perform a kernel memory read.
136+
* Parses a UDP packet containing address and size parameters used to
137+
* perform a kernel memory read. Expects UDP packets to 127.0.0.1:9999.
123138
*/
124139
SEC("xdp")
125-
int read_kernel_memory_xdp(struct xdp_md* ctx) {
126-
int ret;
140+
int read_kernel_memory_xdp(struct xdp_md* ctx) {
127141
void* data = (void*)(long)ctx->data;
128142
void* data_end = (void*)(long)ctx->data_end;
129-
143+
130144
/* Validate Ethernet header */
131145
struct ethhdr *eth = data;
132146
if ((void*)(eth + 1) > data_end) {
133147
return XDP_DROP;
134148
}
135-
136-
/* Skip Ethernet header and validate payload */
137-
struct read_mem_args *args = (struct read_mem_args*)(eth + 1);
149+
150+
/* Check if this is an IP packet */
151+
if (eth->h_proto != bpf_htons(ETH_P_IP)) {
152+
return XDP_PASS;
153+
}
154+
155+
/* Validate and parse IP header */
156+
struct iphdr *ip = (struct iphdr*)(eth + 1);
157+
if ((void*)(ip + 1) > data_end) {
158+
return XDP_DROP;
159+
}
160+
161+
/* Check if this is a UDP packet */
162+
if (ip->protocol != IPPROTO_UDP) {
163+
return XDP_PASS;
164+
}
165+
166+
/* Check if source/dest is loopback */
167+
if (ip->saddr != bpf_htonl(TRIGGER_PACKET_ADDR) || ip->daddr != bpf_htonl(TRIGGER_PACKET_ADDR)) {
168+
return XDP_PASS;
169+
}
170+
171+
/* Validate IP header length */
172+
if (ip->ihl < 5) {
173+
return XDP_DROP;
174+
}
175+
176+
/* Validate UDP header */
177+
struct udphdr *udp = (struct udphdr*)((char*)ip + (ip->ihl * 4));
178+
if ((void*)(udp + 1) > data_end) {
179+
return XDP_DROP;
180+
}
181+
182+
/* Check destination port */
183+
if (udp->dest != bpf_htons(TRIGGER_PACKET_PORT)) {
184+
return XDP_PASS;
185+
}
186+
187+
/* Validate payload */
188+
struct read_mem_args *args = (struct read_mem_args*)(udp + 1);
138189
if ((void*)(args + 1) > data_end) {
139190
return XDP_DROP;
140191
}
141192

142193
__u64 address = args->addr;
143-
__u64 dump_size = args->size;
194+
__u64 dump_size = args->size;
144195

145196
/* Read memory! */
146-
ret = read_memory(address, dump_size);
147-
if(ret) return XDP_DROP;
197+
if (read_memory(address, dump_size)) {
198+
return XDP_DROP;
199+
}
148200

149201
return XDP_PASS;
150202
}

mem.c

Lines changed: 52 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#include <arpa/inet.h>
22
#include <bpf/bpf.h>
3-
#include <linux/if_packet.h>
4-
#include <linux/if_ether.h>
53
#include <net/if.h>
64
#include <sys/stat.h>
75
#include <sys/mman.h>
@@ -24,31 +22,23 @@ struct resource {
2422
struct resource *parent, *sibling, *child;
2523
};
2624

27-
/* Ethernet frame structure for XDP trigger packets */
28-
struct trigger_frame {
29-
struct ethhdr eth_header;
30-
struct read_mem_args args;
31-
char padding[ETH_ZLEN - sizeof(struct ethhdr) - sizeof(struct read_mem_args)];
32-
} __attribute__((packed));
33-
3425
#define IORESOURCE_MEM 0x00000200
3526
#define IORESOURCE_SYSRAM 0x01000000
3627
#define IORESOURCE_BUSY 0x80000000
3728
#define IORESOURCE_SYSTEM_RAM (IORESOURCE_MEM|IORESOURCE_SYSRAM)
38-
#define SYSTEM_RAM_FLAGS (IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY)
29+
#define SYSTEM_RAM_FLAGS (IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY)
3930

4031
extern int check_capability(const cap_value_t cap);
4132

42-
/* eBPF memory read program skeleton and fd of the XDP program */
43-
int read_kernel_memory_xdp_fd;
33+
/* eBPF memory read program skeleton */
4434
struct mem_ebpf *mem_ebpf_skel;
4535

46-
/* XDP attachment and network trigger resources */
47-
int raw_sockfd = -1;
48-
struct bpf_link *bpf_prog_link = NULL;
36+
/* XDP and UDP trigger resources */
37+
int udp_sockfd = -1;
4938
const char *loopback_interface = "lo";
39+
struct bpf_link *bpf_prog_link = NULL;
5040

51-
/* File descriptor and mmap() pointer associated to the eBPF map.*/
41+
/* File descriptor and mmap() pointer associated to the eBPF map */
5242
int read_mem_result_fd;
5343
struct read_mem_result *read_mem_result;
5444

@@ -59,7 +49,7 @@ struct read_mem_result *read_mem_result;
5949
static int64_t v2p_offset;
6050
#endif
6151

62-
/*Address of root of struct resources list (physical memory regions list) */
52+
/* Address of root of struct resources list (physical memory regions list) */
6353
static uintptr_t iomem_resource;
6454

6555
#if defined(__TARGET_ARCH_arm64)
@@ -149,34 +139,26 @@ static int init_mmap() {
149139
}
150140

151141
/*
152-
* init_raw_socket() - Create and bind a raw socket for sending Ethernet frames
142+
* init_udp_socket() - Create and configure UDP socket for sending trigger packets
153143
*
154-
* Creates a raw socket with ETH_P_ALL protocol to send custom Ethernet frames,
155-
* and binds it to loopback interface.
144+
* Creates a UDP socket for sending XDP trigger packets to the loopback interface.
156145
* Returns 0 on success, negative errno value on failure.
157146
*/
158-
static int init_raw_socket(int ifindex) {
159-
struct sockaddr_ll sll;
147+
static int init_udp_socket() {
148+
struct sockaddr_in local_addr;
160149

161-
/* Create raw socket */
162-
raw_sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
163-
if (raw_sockfd < 0) {
164-
perror("Failed to create raw socket for XDP trigger");
150+
/* Create UDP socket */
151+
udp_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
152+
if (udp_sockfd < 0) {
153+
perror("Failed to create UDP socket for XDP trigger");
165154
return -errno;
166155
}
167156

168-
/* Bind raw socket to loopback interface */
169-
memset(&sll, 0, sizeof(sll));
170-
sll.sll_family = AF_PACKET;
171-
sll.sll_ifindex = ifindex;
172-
sll.sll_protocol = htons(ETH_P_ALL);
173-
174-
if (bind(raw_sockfd, (struct sockaddr*)&sll, sizeof(sll)) < 0) {
175-
perror("Failed to bind raw socket to interface");
176-
close(raw_sockfd);
177-
raw_sockfd = -1;
178-
return -errno;
179-
}
157+
/* Setup local address structure for binding*/
158+
memset(&local_addr, 0, sizeof(local_addr));
159+
local_addr.sin_family = AF_INET;
160+
local_addr.sin_addr.s_addr = INADDR_ANY;
161+
local_addr.sin_port = 0;
180162

181163
return 0;
182164
}
@@ -226,11 +208,6 @@ int load_ebpf_mem_progs() {
226208
if (!bpf_prog_link) {
227209
fprintf(stderr, "Failed to attach eBPF Uprobe program, use XDP fallback...\n");
228210

229-
/* Check if can create raw sockets for XDP */
230-
if (check_capability(CAP_NET_RAW) <= 0) {
231-
WARN("LEMON does not have CAP_NET_RAW to create raw sockets for XDP");
232-
}
233-
234211
/* Get loopback interface index by name "lo" (usually 1) */
235212
int ifindex = if_nametoindex(loopback_interface);
236213
if (ifindex <= 0) {
@@ -245,7 +222,7 @@ int load_ebpf_mem_progs() {
245222
}
246223

247224
/* Create socket for sending trigger packets */
248-
if ((ret = init_raw_socket(ifindex))) {
225+
if ((ret = init_udp_socket())) {
249226
return ret;
250227
}
251228
}
@@ -266,17 +243,17 @@ void cleanup_mem_ebpf() {
266243
if(read_mem_result) munmap(read_mem_result, sizeof(struct read_mem_result));
267244
mem_ebpf__destroy(mem_ebpf_skel);
268245
}
269-
246+
270247
/* Destroy bpf_link if it exists*/
271248
if (bpf_prog_link) {
272249
bpf_link__destroy(bpf_prog_link);
273250
bpf_prog_link = NULL;
274251
}
275252

276-
/* Close raw socket if it's open */
277-
if (raw_sockfd) {
278-
close(raw_sockfd);
279-
raw_sockfd = -1;
253+
/* Close UDP socket if it's open */
254+
if (udp_sockfd > 0) {
255+
close(udp_sockfd);
256+
udp_sockfd = -1;
280257
}
281258
}
282259

@@ -298,59 +275,39 @@ uintptr_t phys_to_virt(const uintptr_t phy_addr) {
298275
}
299276

300277
/*
301-
* send_xdp_trigger_packet() - Send Ethernet frame to trigger XDP program
278+
* send_udp_trigger_packet() - Send UDP packets to trigger XDP program
302279
* @addr: Virtual address of the memory region to read
303280
* @size: Size of the memory region to read
304-
*
305-
* Constructs and sends an Ethernet frame with the memory read arguments as payload
306-
* to the loopback interface triggering the XDP program to perform the read.
307-
* Uses a minimal Ethernet frame with broadcast destination.
308-
* Returns 0 on success, negative errno value on failure.
309281
*/
310-
static int send_xdp_trigger_packet(const uintptr_t addr, const size_t size) {
311-
int ifindex;
282+
static int send_udp_trigger_packet(const uintptr_t addr, const size_t size) {
312283
ssize_t sent_bytes;
313-
struct trigger_frame frame;
314-
struct sockaddr_ll dest_addr;
315-
316-
ifindex = if_nametoindex(loopback_interface);
317-
318-
/* Initialize frame structure */
319-
memset(&frame, 0, sizeof(frame));
320-
321-
/* Setup Ethernet header, and use broadcast address for simplicity */
322-
memset(frame.eth_header.h_dest, 0xFF, ETH_ALEN); /* Broadcast destination */
323-
memset(frame.eth_header.h_source, 0x00, ETH_ALEN);
324-
frame.eth_header.h_proto = htons(0x0800);
325-
284+
struct sockaddr_in dest_addr;
285+
struct read_mem_args args;
286+
326287
/* Setup memory read arguments in payload */
327-
frame.args.addr = addr;
328-
frame.args.size = size;
329-
330-
/* Setup destination address */
288+
args.addr = addr;
289+
args.size = size;
290+
291+
/* Setup destination address (loopback) */
331292
memset(&dest_addr, 0, sizeof(dest_addr));
332-
dest_addr.sll_family = AF_PACKET;
333-
dest_addr.sll_ifindex = ifindex;
334-
dest_addr.sll_protocol = htons(ETH_P_ALL);
335-
dest_addr.sll_halen = ETH_ALEN;
336-
memset(dest_addr.sll_addr, 0xFF, ETH_ALEN); /* Broadcast destination */
337-
338-
/* Send the frame */
339-
sent_bytes = sendto(raw_sockfd, &frame, sizeof(frame), 0,
340-
(struct sockaddr *)&dest_addr, sizeof(dest_addr));
341-
293+
dest_addr.sin_family = AF_INET;
294+
dest_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
295+
dest_addr.sin_port = htons(9999);
296+
297+
/* Send the UDP packet */
298+
sent_bytes = sendto(udp_sockfd, &args, sizeof(args), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
299+
342300
if (sent_bytes < 0) {
343-
perror("Failed to send XDP trigger packet");
301+
perror("Failed to send UDP trigger packet");
344302
return -errno;
345303
}
346-
347-
/* For raw packets, partial send should not happen */
348-
if (sent_bytes != sizeof(frame)) {
349-
fprintf(stderr, "Incomplete packet send: %zd of %zu bytes\n",
350-
sent_bytes, sizeof(frame));
304+
305+
/* Check partial send*/
306+
if (sent_bytes != sizeof(args)) {
307+
fprintf(stderr, "Incomplete packet send: %zd of %zu bytes\n", sent_bytes, sizeof(args));
351308
return -EIO;
352309
}
353-
310+
354311
return 0;
355312
}
356313

@@ -365,11 +322,11 @@ static int send_xdp_trigger_packet(const uintptr_t addr, const size_t size) {
365322
*/
366323
int __attribute__((noinline, optnone)) read_kernel_memory(const uintptr_t addr, const size_t size, __u8 **restrict data) {
367324
/* If the Uprobe support is not active in kernel, use XDP to read the memory*/
368-
if(raw_sockfd > 0) {
325+
if(udp_sockfd > 0) {
369326
int ret;
370-
371-
/* Send XDP trigger packet */
372-
ret = send_xdp_trigger_packet(addr, size);
327+
328+
/* Send UDP trigger packet for XDP*/
329+
ret = send_udp_trigger_packet(addr, size);
373330
if (ret < 0) {
374331
read_mem_result->ret_code = ret;
375332
return ret;

0 commit comments

Comments
 (0)