Re: XDP invalid memory access

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On Thu, 16 Jan 2020, Toke Høiland-Jørgensen wrote:

Hi Toke,

> 
> You could also try the xdp-loader in xdp-tools:
> https://github.com/xdp-project/xdp-tools
> 
> It's somewhat basic still, but should be able to at least load a basic
> program - please file a bug report if it fails.

I tried the xdp-tools xdp-loader, when the optlen is global variable, I 
got:
# xdp-loader load enp3s0 tcp_option.o
Couldn't load BPF program: Relocation failed

if I move the optlen, i variable to local variable, I got:

# xdp-loader load enp3s0 tcp_option.o
Couldn't load eBPF object: Invalid argument(-22)

Here is the complete code:

#include <stdint.h>
#include <arpa/inet.h>
#include <asm/byteorder.h>
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/pkt_cls.h>

/*
 * Sample XDP to parse tcp option.
 * compile it with:
 * clang -O2 -emit-llvm -c tcp_option.c -o - |llc -march=bpf -filetype=obj -o tcp_option.o
 * attach it to a device with XDP as:
 * 	ip link set dev lo xdp object tcp_option.o verbose
 */

#define SEC(NAME) __attribute__((section(NAME), used))

#define TCPOPT_EOL        0       /* End of options (1)              */
#define TCPOPT_NOP        1       /* No-op (1)                       */
#define TCPOPT_MAXSEG     2       /* Maximum segment size (4)        */
#define TCPOPT_WSCALE     3       /* Window scaling (3)              */
#define TCPOPT_SACKOK     4       /* Selective ACK permitted (2)     */
#define TCPOPT_SACK       5       /* Actual selective ACK (10-34)    */
#define TCPOPT_TSTAMP     8       /* Timestamp (10)                  */


/* from bpf_helpers.h */

static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
(void *) BPF_FUNC_trace_printk;

static unsigned long long (*bpf_get_prandom_u32)(void) =
(void *) BPF_FUNC_get_prandom_u32;


static int tcp_option(void *data, void *data_end)
{
	struct ethhdr *eth = (struct ethhdr *)data;
	struct iphdr *iph = (struct iphdr *)(eth + 1);
	struct tcphdr *tcphdr = (struct tcphdr *)(iph + 1);
	const __u8 *op;
	int i, optlen;

	/* sanity check needed by the eBPF verifier */
	if ((void *)(tcphdr + 1)  > data_end)
		return 0;

	/* skip non TCP packets */
	if (eth->h_proto != __constant_htons(ETH_P_IP) || iph->protocol != IPPROTO_TCP)
		return 0;

	/* incompatible flags, or PSH already set */
	if (tcphdr->ack || tcphdr->fin || tcphdr->rst || tcphdr->psh)
		return 0;

	if (tcphdr->syn) {
		if (((void *)(tcphdr + 1) + tcphdr->doff*4) > data_end)
			return 0;

		optlen = tcphdr->doff*4 - sizeof(*tcphdr);
		for (i = 0; i < optlen; ) {
			if (op[i] == TCPOPT_EOL ) {
				char fmt[] = "XDP: tcp source : %d tcp option eol\n";
				bpf_trace_printk(fmt, sizeof(fmt), (int)tcphdr->source);
				return 1;
			}
			if (op[i] < 2)
				i++;
			else
				i += op[i+1] ? : 1;
		}
#if 0
		if (tcphdr->doff*4 == 44 || tcphdr->doff*4 == 28) {
			char fmt[] = "XDP: tcp source : %d data offset :%d\n";
			bpf_trace_printk(fmt, sizeof(fmt), (int)tcphdr->source, (int)tcphdr->doff*4);
			return 1;
		}
#endif
	}
	return 0;
}

SEC("prog")
int xdp_main(struct xdp_md *ctx)
{
	void *data_end = (void *)(uintptr_t)ctx->data_end;
	void *data = (void *)(uintptr_t)ctx->data;

	if (tcp_option(data, data_end))
		return XDP_DROP;

	return XDP_PASS;
}


char _license[] SEC("license") = "GPL";

[Index of Archives]     [Linux Networking Development]     [Fedora Linux Users]     [Linux SCTP]     [DCCP]     [Gimp]     [Yosemite Campsites]

  Powered by Linux