mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-25 14:10:08 +01:00
bpf: fix verification errors
This commit is contained in:
parent
d184c21994
commit
efe324eda7
1 changed files with 48 additions and 31 deletions
|
|
@ -61,6 +61,24 @@ struct {
|
|||
#define DBG(fmt, ...)
|
||||
#endif
|
||||
|
||||
/* Macros to read the sk_buff data* pointers, preventing the compiler
|
||||
* from generating a 32bit register access, which fails during verification.
|
||||
* See https://github.com/cilium/cilium/pull/25336
|
||||
*/
|
||||
#define SKB_ACCESS_MEMBER_32(_skb, member) \
|
||||
({ \
|
||||
void *ptr; \
|
||||
\
|
||||
asm volatile("%0 = *(u32 *)(%1 + %2)" \
|
||||
: "=r"(ptr) \
|
||||
: "r"(_skb), "i"(offsetof(struct __sk_buff, member))); \
|
||||
\
|
||||
ptr; \
|
||||
})
|
||||
|
||||
#define SKB_DATA(_skb) SKB_ACCESS_MEMBER_32(_skb, data)
|
||||
#define SKB_DATA_END(_skb) SKB_ACCESS_MEMBER_32(_skb, data_end)
|
||||
|
||||
struct icmpv6_pseudo {
|
||||
struct in6_addr saddr;
|
||||
struct in6_addr daddr;
|
||||
|
|
@ -76,24 +94,22 @@ update_l4_checksum(struct __sk_buff *skb,
|
|||
int ip_type,
|
||||
bool v4to6)
|
||||
{
|
||||
void *data = (void *) (unsigned long long) skb->data;
|
||||
void *data = SKB_DATA(skb);
|
||||
int flags = BPF_F_PSEUDO_HDR;
|
||||
__u16 offset;
|
||||
__u32 csum;
|
||||
|
||||
if (v4to6) {
|
||||
csum = bpf_csum_diff((__be32 *) &iph->saddr,
|
||||
2 * sizeof(__u32),
|
||||
(__be32 *) &ip6h->saddr,
|
||||
2 * sizeof(struct in6_addr),
|
||||
0);
|
||||
void *from_ptr = (__be32 *) &iph->saddr;
|
||||
void *to_ptr = (__be32 *) &ip6h->saddr;
|
||||
|
||||
csum = bpf_csum_diff(from_ptr, 2 * sizeof(__u32), to_ptr, 2 * sizeof(struct in6_addr), 0);
|
||||
offset = (void *) (iph + 1) - data;
|
||||
} else {
|
||||
csum = bpf_csum_diff((__be32 *) &ip6h->saddr,
|
||||
2 * sizeof(struct in6_addr),
|
||||
(__be32 *) &iph->saddr,
|
||||
2 * sizeof(__u32),
|
||||
0);
|
||||
void *from_ptr = (__be32 *) &ip6h->saddr;
|
||||
void *to_ptr = (__be32 *) &iph->saddr;
|
||||
|
||||
csum = bpf_csum_diff(from_ptr, 2 * sizeof(struct in6_addr), to_ptr, 2 * sizeof(__u32), 0);
|
||||
offset = (void *) (ip6h + 1) - data;
|
||||
}
|
||||
|
||||
|
|
@ -119,14 +135,14 @@ update_icmp_checksum(struct __sk_buff *skb,
|
|||
void *icmp_after,
|
||||
bool add)
|
||||
{
|
||||
void *data = (void *) (unsigned long long) skb->data;
|
||||
struct icmpv6_pseudo ph = {.nh = IPPROTO_ICMPV6,
|
||||
.saddr = ip6h->saddr,
|
||||
.daddr = ip6h->daddr,
|
||||
.len = ip6h->payload_len};
|
||||
void *data = SKB_DATA(skb);
|
||||
struct icmpv6_pseudo ph = {.nh = IPPROTO_ICMPV6, .len = ip6h->payload_len};
|
||||
__u16 h_before, h_after, offset;
|
||||
__u32 csum, u_before, u_after;
|
||||
|
||||
__builtin_memcpy(&ph.saddr, &ip6h->saddr, sizeof(struct in6_addr));
|
||||
__builtin_memcpy(&ph.daddr, &ip6h->daddr, sizeof(struct in6_addr));
|
||||
|
||||
/* Do checksum update in two passes: first compute the incremental
|
||||
* checksum update of the ICMPv6 pseudo header, update the checksum
|
||||
* using bpf_l4_csum_replace(), and then do a separate update for the
|
||||
|
|
@ -161,8 +177,7 @@ update_icmp_checksum(struct __sk_buff *skb,
|
|||
static int
|
||||
rewrite_icmp(struct iphdr *iph, struct ipv6hdr *ip6h, struct __sk_buff *skb)
|
||||
{
|
||||
void *data_end = (void *) (unsigned long long) skb->data_end;
|
||||
|
||||
void *data_end = SKB_DATA_END(skb);
|
||||
struct icmphdr old_icmp, *icmp = (void *) (iph + 1);
|
||||
struct icmp6hdr icmp6, *new_icmp6;
|
||||
__u32 mtu;
|
||||
|
|
@ -278,8 +293,8 @@ static __attribute__((always_inline)) inline int
|
|||
clat_handle_v4(struct __sk_buff *skb, struct hdr_cursor *nh)
|
||||
{
|
||||
int ret = TC_ACT_OK;
|
||||
void *data_end = (void *) (unsigned long long) skb->data_end;
|
||||
void *data = (void *) (unsigned long long) skb->data;
|
||||
void *data_end = SKB_DATA_END(skb);
|
||||
void *data = SKB_DATA(skb);
|
||||
int ip_type, iphdr_len, ip_offset;
|
||||
|
||||
struct in6_addr *dst_v6;
|
||||
|
|
@ -363,8 +378,8 @@ clat_handle_v4(struct __sk_buff *skb, struct hdr_cursor *nh)
|
|||
if (bpf_skb_change_proto(skb, bpf_htons(ETH_P_IPV6), 0))
|
||||
goto out;
|
||||
|
||||
data = (void *) (unsigned long long) skb->data;
|
||||
data_end = (void *) (unsigned long long) skb->data_end;
|
||||
data = SKB_DATA(skb);
|
||||
data_end = SKB_DATA_END(skb);
|
||||
|
||||
eth = data;
|
||||
ip6h = data + ip_offset;
|
||||
|
|
@ -400,8 +415,7 @@ rewrite_icmpv6(struct ipv6hdr *ip6h,
|
|||
struct icmphdr **new_icmp_out,
|
||||
struct hdr_cursor *nh)
|
||||
{
|
||||
void *data_end = (void *) (unsigned long long) skb->data_end;
|
||||
|
||||
void *data_end = SKB_DATA_END(skb);
|
||||
struct icmp6hdr old_icmp6, *icmp6 = (void *) (ip6h + 1);
|
||||
struct icmphdr icmp, *new_icmp;
|
||||
__u32 mtu, ptr;
|
||||
|
|
@ -563,7 +577,10 @@ clat_translate_v6(struct __sk_buff *skb,
|
|||
switch (dst_hdr.protocol) {
|
||||
case IPPROTO_ICMPV6:
|
||||
|
||||
new_icmp = (void *) (ip6h + 1);
|
||||
new_icmp = (void *) (ip6h + 1);
|
||||
if ((void *) (new_icmp + 1) > data_end)
|
||||
goto out;
|
||||
|
||||
old_icmp6 = *((struct icmp6hdr *) (void *) new_icmp);
|
||||
if (rewrite_icmpv6(ip6h, skb, &new_icmp, nh))
|
||||
goto out;
|
||||
|
|
@ -631,8 +648,8 @@ static __attribute__((always_inline)) inline int
|
|||
clat_handle_v6(struct __sk_buff *skb, struct hdr_cursor *nh)
|
||||
{
|
||||
int ret = TC_ACT_OK;
|
||||
void *data_end = (void *) (unsigned long long) skb->data_end;
|
||||
void *data = (void *) (unsigned long long) skb->data;
|
||||
void *data_end = SKB_DATA_END(skb);
|
||||
void *data = SKB_DATA(skb);
|
||||
|
||||
struct ethhdr *eth;
|
||||
struct iphdr *iph;
|
||||
|
|
@ -648,8 +665,8 @@ clat_handle_v6(struct __sk_buff *skb, struct hdr_cursor *nh)
|
|||
if (bpf_skb_change_proto(skb, bpf_htons(ETH_P_IP), 0))
|
||||
goto out;
|
||||
|
||||
data = (void *) (unsigned long long) skb->data;
|
||||
data_end = (void *) (unsigned long long) skb->data_end;
|
||||
data = SKB_DATA(skb);
|
||||
data_end = SKB_DATA_END(skb);
|
||||
|
||||
eth = data;
|
||||
iph = data + ip_offset;
|
||||
|
|
@ -667,8 +684,8 @@ out:
|
|||
static __attribute__((always_inline)) inline int
|
||||
clat_handler(struct __sk_buff *skb, bool egress)
|
||||
{
|
||||
void *data_end = (void *) (unsigned long long) skb->data_end;
|
||||
void *data = (void *) (unsigned long long) skb->data;
|
||||
void *data_end = SKB_DATA_END(skb);
|
||||
void *data = SKB_DATA(skb);
|
||||
struct hdr_cursor nh = {.pos = data};
|
||||
struct ethhdr *eth;
|
||||
int eth_type;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue