From: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
To: Vincent Li <mchun.li@gmail.com>
Cc: xdp-newbies@vger.kernel.org, daniel@iogearbox.net,
andriin@fb.com, dsahern@gmail.com
Subject: Re: XDP invalid memory access
Date: Thu, 16 Jan 2020 03:24:59 +0100 [thread overview]
Message-ID: <20200116022459.GA2853@ranger.igk.intel.com> (raw)
In-Reply-To: <CAK86TEf+GY3F8resRW11DNvate5uqSsh=JAQuJHhBuL0sQpvjg@mail.gmail.com>
On Wed, Jan 15, 2020 at 02:11:04PM -0800, Vincent Li wrote:
> Hi,
>
> I am writing a sample XDP program to parse tcp packet options, code
> below, compiled ok, when I attach it to a network interface
>
> #clang -O2 -emit-llvm -c tcp_option.c -o - |llc -march=bpf
> -filetype=obj -o tcp_option.o
>
>
> # ip link set dev enp3s0 xdpgeneric object tcp_option.o verbose
>
>
> Prog section 'prog' rejected: Permission denied (13)!
>
> - Type: 6
>
> - Instructions: 42 (0 over limit)
>
> - License: GPL
>
>
> Verifier analysis:
>
>
> 0: (61) r2 = *(u32 *)(r1 +4)
>
> 1: (61) r1 = *(u32 *)(r1 +0)
>
> 2: (bf) r3 = r1
>
> 3: (07) r3 += 54
>
> 4: (b7) r0 = 2
>
> 5: (2d) if r3 > r2 goto pc+35
>
> R0_w=inv2 R1_w=pkt(id=0,off=0,r=54,imm=0)
> R2_w=pkt_end(id=0,off=0,imm=0) R3_w=pkt(id=0,off=54,r=54,imm=0)
> R10=fp0
>
> 6: (71) r2 = *(u8 *)(r1 +12)
>
> 7: (71) r3 = *(u8 *)(r1 +13)
>
> 8: (67) r3 <<= 8
>
> 9: (4f) r3 |= r2
>
> 10: (b7) r0 = 2
>
> 11: (55) if r3 != 0x8 goto pc+29
>
> R0_w=inv2 R1_w=pkt(id=0,off=0,r=54,imm=0)
> R2_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R3_w=inv8 R10=fp0
>
> 12: (71) r2 = *(u8 *)(r1 +23)
>
> 13: (b7) r0 = 2
>
> 14: (55) if r2 != 0x6 goto pc+26
>
> R0=inv2 R1=pkt(id=0,off=0,r=54,imm=0) R2=inv6 R3=inv8 R10=fp0
>
> 15: (69) r1 = *(u16 *)(r1 +46)
>
> 16: (bf) r2 = r1
>
> 17: (57) r2 &= 7936
>
> 18: (b7) r0 = 2
>
> 19: (55) if r2 != 0x200 goto pc+21
>
> R0_w=inv2 R1_w=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff))
> R2_w=inv512 R3=inv8 R10=fp0
>
> 20: (77) r1 >>= 2
>
> 21: (57) r1 &= 60
>
> 22: (07) r1 += -20
>
> 23: (18) r2 = 0x0
>
> 25: (63) *(u32 *)(r2 +0) = r1
>
> R2 invalid mem access 'inv' <----------------
So it's not out of the bounds access but rather null dereference since r2
has been loaded with 0 on previous insn.
>
> processed 25 insns (limit 1000000) max_states_per_insn 0 total_states
> 1 peak_states 1 mark_read 1
>
>
> it appears optlen = tcphdr->doff*4 - sizeof(*tcphdr); is invalid ? if
> I comment out lines between 60 and 73, no problem with invalid mem
> access
I see that optlen is a global variable. This line might be valid but
you're using iproute2's loader for your XDP program, right? AFAIK it
doesn't have support for BPF global variables, only libbpf does (Daniel,
Andrii? is that true?).
So you have to either make the optlen a local variable or go with writing
the loader part that is based on libbpf usage (see samples/bpf directory
in kernel tree, for example xdp1_user.c).
Could you next time try a little better with the format of data you're
providing? I'm pretty sure other folks would have spotted earlier that
optlen is global if the code was properly formatted :)
To wrap this rant up, making optlen a local var does the job for me.
>
>
>
>
>
> 1 #include <stdint.h>
>
> 2 #include <arpa/inet.h>
>
> 3 #include <asm/byteorder.h>
>
> 4 #include <linux/bpf.h>
>
> 5 #include <linux/if_ether.h>
>
> 6 #include <linux/ip.h>
>
> 7 #include <linux/tcp.h>
>
> 8 #include <linux/pkt_cls.h>
>
> 9
>
> 10 /*
>
> 11 * Sample XDP to parse tcp option.
>
> 12 * compile it with:
>
> 13 * clang -O2 -emit-llvm -c tcp_option.c -o - |llc
> -march=bpf -filetype=obj -o tcp_option.o
>
> 14 * attach it to a device with XDP as:
>
> 15 * ip link set dev lo xdp object tcp_option.o verbose
>
> 16 */
>
> 17
>
> 18 #define SEC(NAME) __attribute__((section(NAME), used))
>
> 19
>
> 20 #define TCPOPT_EOL 0 /* End of options (1) */
>
> 21 #define TCPOPT_NOP 1 /* No-op (1) */
>
> 22 #define TCPOPT_MAXSEG 2 /* Maximum segment size (4) */
>
> 23 #define TCPOPT_WSCALE 3 /* Window scaling (3) */
>
> 24 #define TCPOPT_SACKOK 4 /* Selective ACK permitted (2) */
>
> 25 #define TCPOPT_SACK 5 /* Actual selective ACK (10-34) */
>
> 26 #define TCPOPT_TSTAMP 8 /* Timestamp (10) */
>
> 27
>
> 28
>
> 29 /* from bpf_helpers.h */
>
> 30
>
> 31 static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
>
> 32 (void *) BPF_FUNC_trace_printk;
>
> 33
>
> 34 static unsigned long long (*bpf_get_prandom_u32)(void) =
>
> 35 (void *) BPF_FUNC_get_prandom_u32;
>
> 36
>
> 37 const __u8 *op;
>
> 38 int i, optlen;
>
> 39
>
> 40 static int tcp_option(void *data, void *data_end)
>
> 41 {
>
> 42 struct ethhdr *eth = (struct ethhdr *)data;
>
> 43 struct iphdr *iph = (struct iphdr *)(eth + 1);
>
> 44 struct tcphdr *tcphdr = (struct tcphdr *)(iph + 1);
>
> 45 int tcplen;
>
> 46
>
> 47 /* sanity check needed by the eBPF verifier */
>
> 48 if ((void *)(tcphdr + 1) > data_end)
>
> 49 return 0;
>
> 50
>
> 51 /* skip non TCP packets */
>
> 52 if (eth->h_proto != __constant_htons(ETH_P_IP) || iph->protocol
> != IPPROTO_TCP)
>
> 53 return 0;
>
> 54
>
> 55 /* incompatible flags, or PSH already set */
>
> 56 if (tcphdr->ack || tcphdr->fin || tcphdr->rst || tcphdr->psh)
>
> 57 return 0;
>
> 58
>
> 59 if (tcphdr->syn) {
>
> 60 optlen = tcphdr->doff*4 - sizeof(*tcphdr);
>
> 61 if (!optlen)
>
> 62 return -1;
>
> 63 /*
>
> 64 for (i = 0; i < optlen; ) {
>
> 65 if (op[i] == TCPOPT_EOL) {
>
> 66 char fmt[] = "XDP: tcp opt eol kind seen %d \n";
>
> 67 bpf_trace_printk(fmt, sizeof(fmt), op[i]);
>
> 68 }
>
> 69 if (op[i] < 2)
>
> 70 i++;
>
> 71 else
>
> 72 i += op[i+1] ? : 1;
>
> 73 }
>
> 74 */
>
> 75
>
> 76 char fmt[] = "XDP: tcp syn seen \n";
>
> 77 bpf_trace_printk(fmt, sizeof(fmt));
>
> 78
>
> 79 }
>
> 80
>
> 81 return 0;
>
> 82 }
>
> 83
>
> 84 SEC("prog")
>
> 85 int xdp_main(struct xdp_md *ctx)
>
> 86 {
>
> 87 void *data_end = (void *)(uintptr_t)ctx->data_end;
>
> 88 void *data = (void *)(uintptr_t)ctx->data;
>
> 89
>
> 90 if (tcp_option(data, data_end))
>
> 91 return XDP_DROP;
>
> 92
>
> 93 return XDP_PASS;
>
> 94 }
>
> 95
>
> 96
>
> 97 char _license[] SEC("license") = "GPL";
next prev parent reply other threads:[~2020-01-16 9:32 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-01-15 22:11 XDP invalid memory access Vincent Li
2020-01-15 22:21 ` Toke Høiland-Jørgensen
2020-01-15 22:31 ` Vincent Li
2020-01-16 0:40 ` David Ahern
2020-01-16 1:34 ` Vincent Li
2020-01-16 3:19 ` Vincent Li
2020-01-16 4:22 ` David Ahern
2020-01-16 2:24 ` Maciej Fijalkowski [this message]
2020-01-16 9:45 ` Toke Høiland-Jørgensen
2020-01-16 19:06 ` Vincent Li
2020-01-16 19:20 ` Andrii Nakryiko
2020-01-16 22:10 ` Vincent Li
2020-01-17 11:07 ` Toke Høiland-Jørgensen
2020-01-17 18:14 ` Vincent Li
2020-01-16 17:44 ` Vincent Li
2020-01-16 18:58 ` Vincent Li
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200116022459.GA2853@ranger.igk.intel.com \
--to=maciej.fijalkowski@intel.com \
--cc=andriin@fb.com \
--cc=daniel@iogearbox.net \
--cc=dsahern@gmail.com \
--cc=mchun.li@gmail.com \
--cc=xdp-newbies@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.