Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
Daniel Borkmann says: ==================== The following pull-request contains BPF updates for your *net-next* tree. There is a small merge conflict in libbpf (Cc Andrii so he's in the loop as well): for (i = 1; i <= btf__get_nr_types(btf); i++) { t = (struct btf_type *)btf__type_by_id(btf, i); if (!has_datasec && btf_is_var(t)) { /* replace VAR with INT */ t->info = BTF_INFO_ENC(BTF_KIND_INT, 0, 0); <<<<<<< HEAD /* * using size = 1 is the safest choice, 4 will be too * big and cause kernel BTF validation failure if * original variable took less than 4 bytes */ t->size = 1; *(int *)(t+1) = BTF_INT_ENC(0, 0, 8); } else if (!has_datasec && kind == BTF_KIND_DATASEC) { ======= t->size = sizeof(int); *(int *)(t + 1) = BTF_INT_ENC(0, 0, 32); } else if (!has_datasec && btf_is_datasec(t)) { >>>>>>>72ef80b5ee
/* replace DATASEC with STRUCT */ Conflict is between the two commits1d4126c4e1
("libbpf: sanitize VAR to conservative 1-byte INT") andb03bc6853c
("libbpf: convert libbpf code to use new btf helpers"), so we need to pick the sanitation fixup as well as use the new btf_is_datasec() helper and the whitespace cleanup. Looks like the following: [...] if (!has_datasec && btf_is_var(t)) { /* replace VAR with INT */ t->info = BTF_INFO_ENC(BTF_KIND_INT, 0, 0); /* * using size = 1 is the safest choice, 4 will be too * big and cause kernel BTF validation failure if * original variable took less than 4 bytes */ t->size = 1; *(int *)(t + 1) = BTF_INT_ENC(0, 0, 8); } else if (!has_datasec && btf_is_datasec(t)) { /* replace DATASEC with STRUCT */ [...] The main changes are: 1) Addition of core parts of compile once - run everywhere (co-re) effort, that is, relocation of fields offsets in libbpf as well as exposure of kernel's own BTF via sysfs and loading through libbpf, from Andrii. More info on co-re: http://vger.kernel.org/bpfconf2019.html#session-2 and http://vger.kernel.org/lpc-bpf2018.html#session-2 2) Enable passing input flags to the BPF flow dissector to customize parsing and allowing it to stop early similar to the C based one, from Stanislav. 3) Add a BPF helper function that allows generating SYN cookies from XDP and tc BPF, from Petar. 4) Add devmap hash-based map type for more flexibility in device lookup for redirects, from Toke. 5) Improvements to XDP forwarding sample code now utilizing recently enabled devmap lookups, from Jesper. 6) Add support for reporting the effective cgroup progs in bpftool, from Jakub and Takshak. 7) Fix reading kernel config from bpftool via /proc/config.gz, from Peter. 8) Fix AF_XDP umem pages mapping for 32 bit architectures, from Ivan. 9) Follow-up to add two more BPF loop tests for the selftest suite, from Alexei. 10) Add perf event output helper also for other skb-based program types, from Allan. 11) Fix a co-re related compilation error in selftests, from Yonghong. ==================== Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
This commit is contained in:
@@ -65,8 +65,8 @@ struct {
|
||||
} jmp_table SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 1024);
|
||||
__type(key, __u32);
|
||||
__type(value, struct bpf_flow_keys);
|
||||
} last_dissection SEC(".maps");
|
||||
@@ -74,15 +74,20 @@ struct {
|
||||
static __always_inline int export_flow_keys(struct bpf_flow_keys *keys,
|
||||
int ret)
|
||||
{
|
||||
struct bpf_flow_keys *val;
|
||||
__u32 key = 0;
|
||||
__u32 key = (__u32)(keys->sport) << 16 | keys->dport;
|
||||
struct bpf_flow_keys val;
|
||||
|
||||
val = bpf_map_lookup_elem(&last_dissection, &key);
|
||||
if (val)
|
||||
memcpy(val, keys, sizeof(*val));
|
||||
memcpy(&val, keys, sizeof(val));
|
||||
bpf_map_update_elem(&last_dissection, &key, &val, BPF_ANY);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define IPV6_FLOWLABEL_MASK __bpf_constant_htonl(0x000FFFFF)
|
||||
static inline __be32 ip6_flowlabel(const struct ipv6hdr *hdr)
|
||||
{
|
||||
return *(__be32 *)hdr & IPV6_FLOWLABEL_MASK;
|
||||
}
|
||||
|
||||
static __always_inline void *bpf_flow_dissect_get_header(struct __sk_buff *skb,
|
||||
__u16 hdr_size,
|
||||
void *buffer)
|
||||
@@ -153,7 +158,6 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto)
|
||||
struct tcphdr *tcp, _tcp;
|
||||
struct udphdr *udp, _udp;
|
||||
|
||||
keys->ip_proto = proto;
|
||||
switch (proto) {
|
||||
case IPPROTO_ICMP:
|
||||
icmp = bpf_flow_dissect_get_header(skb, sizeof(*icmp), &_icmp);
|
||||
@@ -162,9 +166,15 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto)
|
||||
return export_flow_keys(keys, BPF_OK);
|
||||
case IPPROTO_IPIP:
|
||||
keys->is_encap = true;
|
||||
if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP)
|
||||
return export_flow_keys(keys, BPF_OK);
|
||||
|
||||
return parse_eth_proto(skb, bpf_htons(ETH_P_IP));
|
||||
case IPPROTO_IPV6:
|
||||
keys->is_encap = true;
|
||||
if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP)
|
||||
return export_flow_keys(keys, BPF_OK);
|
||||
|
||||
return parse_eth_proto(skb, bpf_htons(ETH_P_IPV6));
|
||||
case IPPROTO_GRE:
|
||||
gre = bpf_flow_dissect_get_header(skb, sizeof(*gre), &_gre);
|
||||
@@ -184,6 +194,8 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto)
|
||||
keys->thoff += 4; /* Step over sequence number */
|
||||
|
||||
keys->is_encap = true;
|
||||
if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP)
|
||||
return export_flow_keys(keys, BPF_OK);
|
||||
|
||||
if (gre->proto == bpf_htons(ETH_P_TEB)) {
|
||||
eth = bpf_flow_dissect_get_header(skb, sizeof(*eth),
|
||||
@@ -231,7 +243,6 @@ static __always_inline int parse_ipv6_proto(struct __sk_buff *skb, __u8 nexthdr)
|
||||
{
|
||||
struct bpf_flow_keys *keys = skb->flow_keys;
|
||||
|
||||
keys->ip_proto = nexthdr;
|
||||
switch (nexthdr) {
|
||||
case IPPROTO_HOPOPTS:
|
||||
case IPPROTO_DSTOPTS:
|
||||
@@ -266,6 +277,7 @@ PROG(IP)(struct __sk_buff *skb)
|
||||
keys->addr_proto = ETH_P_IP;
|
||||
keys->ipv4_src = iph->saddr;
|
||||
keys->ipv4_dst = iph->daddr;
|
||||
keys->ip_proto = iph->protocol;
|
||||
|
||||
keys->thoff += iph->ihl << 2;
|
||||
if (data + keys->thoff > data_end)
|
||||
@@ -273,13 +285,20 @@ PROG(IP)(struct __sk_buff *skb)
|
||||
|
||||
if (iph->frag_off & bpf_htons(IP_MF | IP_OFFSET)) {
|
||||
keys->is_frag = true;
|
||||
if (iph->frag_off & bpf_htons(IP_OFFSET))
|
||||
if (iph->frag_off & bpf_htons(IP_OFFSET)) {
|
||||
/* From second fragment on, packets do not have headers
|
||||
* we can parse.
|
||||
*/
|
||||
done = true;
|
||||
else
|
||||
} else {
|
||||
keys->is_first_frag = true;
|
||||
/* No need to parse fragmented packet unless
|
||||
* explicitly asked for.
|
||||
*/
|
||||
if (!(keys->flags &
|
||||
BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG))
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (done)
|
||||
@@ -301,6 +320,11 @@ PROG(IPV6)(struct __sk_buff *skb)
|
||||
memcpy(&keys->ipv6_src, &ip6h->saddr, 2*sizeof(ip6h->saddr));
|
||||
|
||||
keys->thoff += sizeof(struct ipv6hdr);
|
||||
keys->ip_proto = ip6h->nexthdr;
|
||||
keys->flow_label = ip6_flowlabel(ip6h);
|
||||
|
||||
if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL)
|
||||
return export_flow_keys(keys, BPF_OK);
|
||||
|
||||
return parse_ipv6_proto(skb, ip6h->nexthdr);
|
||||
}
|
||||
@@ -317,7 +341,8 @@ PROG(IPV6OP)(struct __sk_buff *skb)
|
||||
/* hlen is in 8-octets and does not include the first 8 bytes
|
||||
* of the header
|
||||
*/
|
||||
skb->flow_keys->thoff += (1 + ip6h->hdrlen) << 3;
|
||||
keys->thoff += (1 + ip6h->hdrlen) << 3;
|
||||
keys->ip_proto = ip6h->nexthdr;
|
||||
|
||||
return parse_ipv6_proto(skb, ip6h->nexthdr);
|
||||
}
|
||||
@@ -333,9 +358,18 @@ PROG(IPV6FR)(struct __sk_buff *skb)
|
||||
|
||||
keys->thoff += sizeof(*fragh);
|
||||
keys->is_frag = true;
|
||||
if (!(fragh->frag_off & bpf_htons(IP6_OFFSET)))
|
||||
keys->ip_proto = fragh->nexthdr;
|
||||
|
||||
if (!(fragh->frag_off & bpf_htons(IP6_OFFSET))) {
|
||||
keys->is_first_frag = true;
|
||||
|
||||
/* No need to parse fragmented packet unless
|
||||
* explicitly asked for.
|
||||
*/
|
||||
if (!(keys->flags & BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG))
|
||||
return export_flow_keys(keys, BPF_OK);
|
||||
}
|
||||
|
||||
return parse_ipv6_proto(skb, fragh->nexthdr);
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_arrays x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_arrays___diff_arr_dim x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_arrays___diff_arr_val_sz x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_arrays___err_non_array x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_arrays___err_too_shallow x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_arrays___err_too_small x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_arrays___err_wrong_val_type1 x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_arrays___err_wrong_val_type2 x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_flavors x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_flavors__err_wrong_name x) {}
|
3
tools/testing/selftests/bpf/progs/btf__core_reloc_ints.c
Normal file
3
tools/testing/selftests/bpf/progs/btf__core_reloc_ints.c
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_ints x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_ints___bool x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_ints___err_bitfield x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_ints___err_wrong_sz_16 x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_ints___err_wrong_sz_32 x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_ints___err_wrong_sz_64 x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_ints___err_wrong_sz_8 x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_ints___reverse_sign x) {}
|
5
tools/testing/selftests/bpf/progs/btf__core_reloc_misc.c
Normal file
5
tools/testing/selftests/bpf/progs/btf__core_reloc_misc.c
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f1(struct core_reloc_misc___a x) {}
|
||||
void f2(struct core_reloc_misc___b x) {}
|
||||
void f3(struct core_reloc_misc_extensible x) {}
|
3
tools/testing/selftests/bpf/progs/btf__core_reloc_mods.c
Normal file
3
tools/testing/selftests/bpf/progs/btf__core_reloc_mods.c
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_mods x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_mods___mod_swap x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_mods___typedefs x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___anon_embed x) {}
|
@@ -0,0 +1,5 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f1(struct core_reloc_nesting___dup_compat_types x) {}
|
||||
void f2(struct core_reloc_nesting___dup_compat_types__2 x) {}
|
||||
void f3(struct core_reloc_nesting___dup_compat_types__3 x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___err_array_container x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___err_array_field x) {}
|
@@ -0,0 +1,4 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f1(struct core_reloc_nesting___err_dup_incompat_types__1 x) {}
|
||||
void f2(struct core_reloc_nesting___err_dup_incompat_types__2 x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___err_missing_container x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___err_missing_field x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___err_nonstruct_container x) {}
|
@@ -0,0 +1,4 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f1(struct core_reloc_nesting___err_partial_match_dups__a x) {}
|
||||
void f2(struct core_reloc_nesting___err_partial_match_dups__b x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___err_too_deep x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___extra_nesting x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_nesting___struct_union_mixup x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_primitives x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_primitives___diff_enum_def x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_primitives___diff_func_proto x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_primitives___diff_ptr_type x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_primitives___err_non_enum x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_primitives___err_non_int x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_primitives___err_non_ptr x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_ptr_as_arr x) {}
|
@@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_ptr_as_arr___diff_sz x) {}
|
667
tools/testing/selftests/bpf/progs/core_reloc_types.h
Normal file
667
tools/testing/selftests/bpf/progs/core_reloc_types.h
Normal file
@@ -0,0 +1,667 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*
|
||||
* FLAVORS
|
||||
*/
|
||||
struct core_reloc_flavors {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
};
|
||||
|
||||
/* this is not a flavor, as it doesn't have triple underscore */
|
||||
struct core_reloc_flavors__err_wrong_name {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
};
|
||||
|
||||
/*
|
||||
* NESTING
|
||||
*/
|
||||
/* original set up, used to record relocations in BPF program */
|
||||
struct core_reloc_nesting_substruct {
|
||||
int a;
|
||||
};
|
||||
|
||||
union core_reloc_nesting_subunion {
|
||||
int b;
|
||||
};
|
||||
|
||||
struct core_reloc_nesting {
|
||||
union {
|
||||
struct core_reloc_nesting_substruct a;
|
||||
} a;
|
||||
struct {
|
||||
union core_reloc_nesting_subunion b;
|
||||
} b;
|
||||
};
|
||||
|
||||
/* inlined anonymous struct/union instead of named structs in original */
|
||||
struct core_reloc_nesting___anon_embed {
|
||||
int __just_for_padding;
|
||||
union {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
struct {
|
||||
union {
|
||||
int b;
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
/* different mix of nested structs/unions than in original */
|
||||
struct core_reloc_nesting___struct_union_mixup {
|
||||
int __a;
|
||||
struct {
|
||||
int __a;
|
||||
union {
|
||||
char __a;
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
int __b;
|
||||
union {
|
||||
int __b;
|
||||
union {
|
||||
char __b;
|
||||
int b;
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
/* extra anon structs/unions, but still valid a.a.a and b.b.b accessors */
|
||||
struct core_reloc_nesting___extra_nesting {
|
||||
int __padding;
|
||||
struct {
|
||||
struct {
|
||||
struct {
|
||||
struct {
|
||||
union {
|
||||
int a;
|
||||
} a;
|
||||
};
|
||||
};
|
||||
} a;
|
||||
int __some_more;
|
||||
struct {
|
||||
union {
|
||||
union {
|
||||
union {
|
||||
struct {
|
||||
int b;
|
||||
};
|
||||
} b;
|
||||
};
|
||||
} b;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* three flavors of same struct with different structure but same layout for
|
||||
* a.a.a and b.b.b, thus successfully resolved and relocatable */
|
||||
struct core_reloc_nesting___dup_compat_types {
|
||||
char __just_for_padding;
|
||||
/* 3 more bytes of padding */
|
||||
struct {
|
||||
struct {
|
||||
int a; /* offset 4 */
|
||||
} a;
|
||||
} a;
|
||||
long long __more_padding;
|
||||
struct {
|
||||
struct {
|
||||
int b; /* offset 16 */
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
struct core_reloc_nesting___dup_compat_types__2 {
|
||||
int __aligned_padding;
|
||||
struct {
|
||||
int __trickier_noop[0];
|
||||
struct {
|
||||
char __some_more_noops[0];
|
||||
int a; /* offset 4 */
|
||||
} a;
|
||||
} a;
|
||||
int __more_padding;
|
||||
struct {
|
||||
struct {
|
||||
struct {
|
||||
int __critical_padding;
|
||||
int b; /* offset 16 */
|
||||
} b;
|
||||
int __does_not_matter;
|
||||
};
|
||||
} b;
|
||||
int __more_irrelevant_stuff;
|
||||
};
|
||||
|
||||
struct core_reloc_nesting___dup_compat_types__3 {
|
||||
char __correct_padding[4];
|
||||
struct {
|
||||
struct {
|
||||
int a; /* offset 4 */
|
||||
} a;
|
||||
} a;
|
||||
/* 8 byte padding due to next struct's alignment */
|
||||
struct {
|
||||
struct {
|
||||
int b;
|
||||
} b;
|
||||
} b __attribute__((aligned(16)));
|
||||
};
|
||||
|
||||
/* b.b.b field is missing */
|
||||
struct core_reloc_nesting___err_missing_field {
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
struct {
|
||||
struct {
|
||||
int x;
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
/* b.b.b field is an array of integers instead of plain int */
|
||||
struct core_reloc_nesting___err_array_field {
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
struct {
|
||||
struct {
|
||||
int b[1];
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
/* middle b container is missing */
|
||||
struct core_reloc_nesting___err_missing_container {
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
struct {
|
||||
int x;
|
||||
} b;
|
||||
};
|
||||
|
||||
/* middle b container is referenced through pointer instead of being embedded */
|
||||
struct core_reloc_nesting___err_nonstruct_container {
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
struct {
|
||||
struct {
|
||||
int b;
|
||||
} *b;
|
||||
} b;
|
||||
};
|
||||
|
||||
/* middle b container is an array of structs instead of plain struct */
|
||||
struct core_reloc_nesting___err_array_container {
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
struct {
|
||||
struct {
|
||||
int b;
|
||||
} b[1];
|
||||
} b;
|
||||
};
|
||||
|
||||
/* two flavors of same struct with incompatible layout for b.b.b */
|
||||
struct core_reloc_nesting___err_dup_incompat_types__1 {
|
||||
struct {
|
||||
struct {
|
||||
int a; /* offset 0 */
|
||||
} a;
|
||||
} a;
|
||||
struct {
|
||||
struct {
|
||||
int b; /* offset 4 */
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
struct core_reloc_nesting___err_dup_incompat_types__2 {
|
||||
struct {
|
||||
struct {
|
||||
int a; /* offset 0 */
|
||||
} a;
|
||||
} a;
|
||||
int __extra_padding;
|
||||
struct {
|
||||
struct {
|
||||
int b; /* offset 8 (!) */
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
/* two flavors of same struct having one of a.a.a and b.b.b, but not both */
|
||||
struct core_reloc_nesting___err_partial_match_dups__a {
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
};
|
||||
|
||||
struct core_reloc_nesting___err_partial_match_dups__b {
|
||||
struct {
|
||||
struct {
|
||||
int b;
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
struct core_reloc_nesting___err_too_deep {
|
||||
struct {
|
||||
struct {
|
||||
int a;
|
||||
} a;
|
||||
} a;
|
||||
/* 65 levels of nestedness for b.b.b */
|
||||
struct {
|
||||
struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
struct { struct { struct { struct { struct {
|
||||
/* this one is one too much */
|
||||
struct {
|
||||
int b;
|
||||
};
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
}; }; }; }; };
|
||||
} b;
|
||||
} b;
|
||||
};
|
||||
|
||||
/*
|
||||
* ARRAYS
|
||||
*/
|
||||
struct core_reloc_arrays_output {
|
||||
int a2;
|
||||
char b123;
|
||||
int c1c;
|
||||
int d00d;
|
||||
};
|
||||
|
||||
struct core_reloc_arrays_substruct {
|
||||
int c;
|
||||
int d;
|
||||
};
|
||||
|
||||
struct core_reloc_arrays {
|
||||
int a[5];
|
||||
char b[2][3][4];
|
||||
struct core_reloc_arrays_substruct c[3];
|
||||
struct core_reloc_arrays_substruct d[1][2];
|
||||
};
|
||||
|
||||
/* bigger array dimensions */
|
||||
struct core_reloc_arrays___diff_arr_dim {
|
||||
int a[7];
|
||||
char b[3][4][5];
|
||||
struct core_reloc_arrays_substruct c[4];
|
||||
struct core_reloc_arrays_substruct d[2][3];
|
||||
};
|
||||
|
||||
/* different size of array's value (struct) */
|
||||
struct core_reloc_arrays___diff_arr_val_sz {
|
||||
int a[5];
|
||||
char b[2][3][4];
|
||||
struct {
|
||||
int __padding1;
|
||||
int c;
|
||||
int __padding2;
|
||||
} c[3];
|
||||
struct {
|
||||
int __padding1;
|
||||
int d;
|
||||
int __padding2;
|
||||
} d[1][2];
|
||||
};
|
||||
|
||||
struct core_reloc_arrays___err_too_small {
|
||||
int a[2]; /* this one is too small */
|
||||
char b[2][3][4];
|
||||
struct core_reloc_arrays_substruct c[3];
|
||||
struct core_reloc_arrays_substruct d[1][2];
|
||||
};
|
||||
|
||||
struct core_reloc_arrays___err_too_shallow {
|
||||
int a[5];
|
||||
char b[2][3]; /* this one lacks one dimension */
|
||||
struct core_reloc_arrays_substruct c[3];
|
||||
struct core_reloc_arrays_substruct d[1][2];
|
||||
};
|
||||
|
||||
struct core_reloc_arrays___err_non_array {
|
||||
int a; /* not an array */
|
||||
char b[2][3][4];
|
||||
struct core_reloc_arrays_substruct c[3];
|
||||
struct core_reloc_arrays_substruct d[1][2];
|
||||
};
|
||||
|
||||
struct core_reloc_arrays___err_wrong_val_type1 {
|
||||
char a[5]; /* char instead of int */
|
||||
char b[2][3][4];
|
||||
struct core_reloc_arrays_substruct c[3];
|
||||
struct core_reloc_arrays_substruct d[1][2];
|
||||
};
|
||||
|
||||
struct core_reloc_arrays___err_wrong_val_type2 {
|
||||
int a[5];
|
||||
char b[2][3][4];
|
||||
int c[3]; /* value is not a struct */
|
||||
struct core_reloc_arrays_substruct d[1][2];
|
||||
};
|
||||
|
||||
/*
|
||||
* PRIMITIVES
|
||||
*/
|
||||
enum core_reloc_primitives_enum {
|
||||
A = 0,
|
||||
B = 1,
|
||||
};
|
||||
|
||||
struct core_reloc_primitives {
|
||||
char a;
|
||||
int b;
|
||||
enum core_reloc_primitives_enum c;
|
||||
void *d;
|
||||
int (*f)(const char *);
|
||||
};
|
||||
|
||||
struct core_reloc_primitives___diff_enum_def {
|
||||
char a;
|
||||
int b;
|
||||
void *d;
|
||||
int (*f)(const char *);
|
||||
enum {
|
||||
X = 100,
|
||||
Y = 200,
|
||||
} c; /* inline enum def with differing set of values */
|
||||
};
|
||||
|
||||
struct core_reloc_primitives___diff_func_proto {
|
||||
void (*f)(int); /* incompatible function prototype */
|
||||
void *d;
|
||||
enum core_reloc_primitives_enum c;
|
||||
int b;
|
||||
char a;
|
||||
};
|
||||
|
||||
struct core_reloc_primitives___diff_ptr_type {
|
||||
const char * const d; /* different pointee type + modifiers */
|
||||
char a;
|
||||
int b;
|
||||
enum core_reloc_primitives_enum c;
|
||||
int (*f)(const char *);
|
||||
};
|
||||
|
||||
struct core_reloc_primitives___err_non_enum {
|
||||
char a[1];
|
||||
int b;
|
||||
int c; /* int instead of enum */
|
||||
void *d;
|
||||
int (*f)(const char *);
|
||||
};
|
||||
|
||||
struct core_reloc_primitives___err_non_int {
|
||||
char a[1];
|
||||
int *b; /* ptr instead of int */
|
||||
enum core_reloc_primitives_enum c;
|
||||
void *d;
|
||||
int (*f)(const char *);
|
||||
};
|
||||
|
||||
struct core_reloc_primitives___err_non_ptr {
|
||||
char a[1];
|
||||
int b;
|
||||
enum core_reloc_primitives_enum c;
|
||||
int d; /* int instead of ptr */
|
||||
int (*f)(const char *);
|
||||
};
|
||||
|
||||
/*
|
||||
* MODS
|
||||
*/
|
||||
struct core_reloc_mods_output {
|
||||
int a, b, c, d, e, f, g, h;
|
||||
};
|
||||
|
||||
typedef const int int_t;
|
||||
typedef const char *char_ptr_t;
|
||||
typedef const int arr_t[7];
|
||||
|
||||
struct core_reloc_mods_substruct {
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
} core_reloc_mods_substruct_t;
|
||||
|
||||
struct core_reloc_mods {
|
||||
int a;
|
||||
int_t b;
|
||||
char *c;
|
||||
char_ptr_t d;
|
||||
int e[3];
|
||||
arr_t f;
|
||||
struct core_reloc_mods_substruct g;
|
||||
core_reloc_mods_substruct_t h;
|
||||
};
|
||||
|
||||
/* a/b, c/d, e/f, and g/h pairs are swapped */
|
||||
struct core_reloc_mods___mod_swap {
|
||||
int b;
|
||||
int_t a;
|
||||
char *d;
|
||||
char_ptr_t c;
|
||||
int f[3];
|
||||
arr_t e;
|
||||
struct {
|
||||
int y;
|
||||
int x;
|
||||
} h;
|
||||
core_reloc_mods_substruct_t g;
|
||||
};
|
||||
|
||||
typedef int int1_t;
|
||||
typedef int1_t int2_t;
|
||||
typedef int2_t int3_t;
|
||||
|
||||
typedef int arr1_t[5];
|
||||
typedef arr1_t arr2_t;
|
||||
typedef arr2_t arr3_t;
|
||||
typedef arr3_t arr4_t;
|
||||
|
||||
typedef const char * const volatile fancy_char_ptr_t;
|
||||
|
||||
typedef core_reloc_mods_substruct_t core_reloc_mods_substruct_tt;
|
||||
|
||||
/* we need more typedefs */
|
||||
struct core_reloc_mods___typedefs {
|
||||
core_reloc_mods_substruct_tt g;
|
||||
core_reloc_mods_substruct_tt h;
|
||||
arr4_t f;
|
||||
arr4_t e;
|
||||
fancy_char_ptr_t d;
|
||||
fancy_char_ptr_t c;
|
||||
int3_t b;
|
||||
int3_t a;
|
||||
};
|
||||
|
||||
/*
|
||||
* PTR_AS_ARR
|
||||
*/
|
||||
struct core_reloc_ptr_as_arr {
|
||||
int a;
|
||||
};
|
||||
|
||||
struct core_reloc_ptr_as_arr___diff_sz {
|
||||
int :32; /* padding */
|
||||
char __some_more_padding;
|
||||
int a;
|
||||
};
|
||||
|
||||
/*
|
||||
* INTS
|
||||
*/
|
||||
struct core_reloc_ints {
|
||||
uint8_t u8_field;
|
||||
int8_t s8_field;
|
||||
uint16_t u16_field;
|
||||
int16_t s16_field;
|
||||
uint32_t u32_field;
|
||||
int32_t s32_field;
|
||||
uint64_t u64_field;
|
||||
int64_t s64_field;
|
||||
};
|
||||
|
||||
/* signed/unsigned types swap */
|
||||
struct core_reloc_ints___reverse_sign {
|
||||
int8_t u8_field;
|
||||
uint8_t s8_field;
|
||||
int16_t u16_field;
|
||||
uint16_t s16_field;
|
||||
int32_t u32_field;
|
||||
uint32_t s32_field;
|
||||
int64_t u64_field;
|
||||
uint64_t s64_field;
|
||||
};
|
||||
|
||||
struct core_reloc_ints___bool {
|
||||
bool u8_field; /* bool instead of uint8 */
|
||||
int8_t s8_field;
|
||||
uint16_t u16_field;
|
||||
int16_t s16_field;
|
||||
uint32_t u32_field;
|
||||
int32_t s32_field;
|
||||
uint64_t u64_field;
|
||||
int64_t s64_field;
|
||||
};
|
||||
|
||||
struct core_reloc_ints___err_bitfield {
|
||||
uint8_t u8_field;
|
||||
int8_t s8_field;
|
||||
uint16_t u16_field;
|
||||
int16_t s16_field;
|
||||
uint32_t u32_field: 32; /* bitfields are not supported */
|
||||
int32_t s32_field;
|
||||
uint64_t u64_field;
|
||||
int64_t s64_field;
|
||||
};
|
||||
|
||||
struct core_reloc_ints___err_wrong_sz_8 {
|
||||
uint16_t u8_field; /* not 8-bit anymore */
|
||||
int16_t s8_field; /* not 8-bit anymore */
|
||||
|
||||
uint16_t u16_field;
|
||||
int16_t s16_field;
|
||||
uint32_t u32_field;
|
||||
int32_t s32_field;
|
||||
uint64_t u64_field;
|
||||
int64_t s64_field;
|
||||
};
|
||||
|
||||
struct core_reloc_ints___err_wrong_sz_16 {
|
||||
uint8_t u8_field;
|
||||
int8_t s8_field;
|
||||
|
||||
uint32_t u16_field; /* not 16-bit anymore */
|
||||
int32_t s16_field; /* not 16-bit anymore */
|
||||
|
||||
uint32_t u32_field;
|
||||
int32_t s32_field;
|
||||
uint64_t u64_field;
|
||||
int64_t s64_field;
|
||||
};
|
||||
|
||||
struct core_reloc_ints___err_wrong_sz_32 {
|
||||
uint8_t u8_field;
|
||||
int8_t s8_field;
|
||||
uint16_t u16_field;
|
||||
int16_t s16_field;
|
||||
|
||||
uint64_t u32_field; /* not 32-bit anymore */
|
||||
int64_t s32_field; /* not 32-bit anymore */
|
||||
|
||||
uint64_t u64_field;
|
||||
int64_t s64_field;
|
||||
};
|
||||
|
||||
struct core_reloc_ints___err_wrong_sz_64 {
|
||||
uint8_t u8_field;
|
||||
int8_t s8_field;
|
||||
uint16_t u16_field;
|
||||
int16_t s16_field;
|
||||
uint32_t u32_field;
|
||||
int32_t s32_field;
|
||||
|
||||
uint32_t u64_field; /* not 64-bit anymore */
|
||||
int32_t s64_field; /* not 64-bit anymore */
|
||||
};
|
||||
|
||||
/*
|
||||
* MISC
|
||||
*/
|
||||
struct core_reloc_misc_output {
|
||||
int a, b, c;
|
||||
};
|
||||
|
||||
struct core_reloc_misc___a {
|
||||
int a1;
|
||||
int a2;
|
||||
};
|
||||
|
||||
struct core_reloc_misc___b {
|
||||
int b1;
|
||||
int b2;
|
||||
};
|
||||
|
||||
/* this one extends core_reloc_misc_extensible struct from BPF prog */
|
||||
struct core_reloc_misc_extensible {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
int d;
|
||||
};
|
18
tools/testing/selftests/bpf/progs/loop4.c
Normal file
18
tools/testing/selftests/bpf/progs/loop4.c
Normal file
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
#include <linux/bpf.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
SEC("socket")
|
||||
int combinations(volatile struct __sk_buff* skb)
|
||||
{
|
||||
int ret = 0, i;
|
||||
|
||||
#pragma nounroll
|
||||
for (i = 0; i < 20; i++)
|
||||
if (skb->len)
|
||||
ret |= 1 << i;
|
||||
return ret;
|
||||
}
|
32
tools/testing/selftests/bpf/progs/loop5.c
Normal file
32
tools/testing/selftests/bpf/progs/loop5.c
Normal file
@@ -0,0 +1,32 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
#include <linux/bpf.h>
|
||||
#include "bpf_helpers.h"
|
||||
#define barrier() __asm__ __volatile__("": : :"memory")
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
SEC("socket")
|
||||
int while_true(volatile struct __sk_buff* skb)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (1) {
|
||||
if (skb->len)
|
||||
i += 3;
|
||||
else
|
||||
i += 7;
|
||||
if (i == 9)
|
||||
break;
|
||||
barrier();
|
||||
if (i == 10)
|
||||
break;
|
||||
barrier();
|
||||
if (i == 13)
|
||||
break;
|
||||
barrier();
|
||||
if (i == 14)
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
@@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <linux/bpf.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
@@ -42,6 +44,14 @@ int _getsockopt(struct bpf_sockopt *ctx)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION) {
|
||||
/* Not interested in SOL_TCP:TCP_CONGESTION;
|
||||
* let next BPF program in the cgroup chain or kernel
|
||||
* handle it.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ctx->level != SOL_CUSTOM)
|
||||
return 0; /* EPERM, deny everything except custom level */
|
||||
|
||||
@@ -91,6 +101,18 @@ int _setsockopt(struct bpf_sockopt *ctx)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION) {
|
||||
/* Always use cubic */
|
||||
|
||||
if (optval + 5 > optval_end)
|
||||
return 0; /* EPERM, bounds check */
|
||||
|
||||
memcpy(optval, "cubic", 5);
|
||||
ctx->optlen = 5;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ctx->level != SOL_CUSTOM)
|
||||
return 0; /* EPERM, deny everything except custom level */
|
||||
|
||||
|
55
tools/testing/selftests/bpf/progs/test_core_reloc_arrays.c
Normal file
55
tools/testing/selftests/bpf/progs/test_core_reloc_arrays.c
Normal file
@@ -0,0 +1,55 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <stdint.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
static volatile struct data {
|
||||
char in[256];
|
||||
char out[256];
|
||||
} data;
|
||||
|
||||
struct core_reloc_arrays_output {
|
||||
int a2;
|
||||
char b123;
|
||||
int c1c;
|
||||
int d00d;
|
||||
};
|
||||
|
||||
struct core_reloc_arrays_substruct {
|
||||
int c;
|
||||
int d;
|
||||
};
|
||||
|
||||
struct core_reloc_arrays {
|
||||
int a[5];
|
||||
char b[2][3][4];
|
||||
struct core_reloc_arrays_substruct c[3];
|
||||
struct core_reloc_arrays_substruct d[1][2];
|
||||
};
|
||||
|
||||
SEC("raw_tracepoint/sys_enter")
|
||||
int test_core_arrays(void *ctx)
|
||||
{
|
||||
struct core_reloc_arrays *in = (void *)&data.in;
|
||||
struct core_reloc_arrays_output *out = (void *)&data.out;
|
||||
|
||||
/* in->a[2] */
|
||||
if (BPF_CORE_READ(&out->a2, &in->a[2]))
|
||||
return 1;
|
||||
/* in->b[1][2][3] */
|
||||
if (BPF_CORE_READ(&out->b123, &in->b[1][2][3]))
|
||||
return 1;
|
||||
/* in->c[1].c */
|
||||
if (BPF_CORE_READ(&out->c1c, &in->c[1].c))
|
||||
return 1;
|
||||
/* in->d[0][0].d */
|
||||
if (BPF_CORE_READ(&out->d00d, &in->d[0][0].d))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
62
tools/testing/selftests/bpf/progs/test_core_reloc_flavors.c
Normal file
62
tools/testing/selftests/bpf/progs/test_core_reloc_flavors.c
Normal file
@@ -0,0 +1,62 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <stdint.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
static volatile struct data {
|
||||
char in[256];
|
||||
char out[256];
|
||||
} data;
|
||||
|
||||
struct core_reloc_flavors {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
};
|
||||
|
||||
/* local flavor with reversed layout */
|
||||
struct core_reloc_flavors___reversed {
|
||||
int c;
|
||||
int b;
|
||||
int a;
|
||||
};
|
||||
|
||||
/* local flavor with nested/overlapping layout */
|
||||
struct core_reloc_flavors___weird {
|
||||
struct {
|
||||
int b;
|
||||
};
|
||||
/* a and c overlap in local flavor, but this should still work
|
||||
* correctly with target original flavor
|
||||
*/
|
||||
union {
|
||||
int a;
|
||||
int c;
|
||||
};
|
||||
};
|
||||
|
||||
SEC("raw_tracepoint/sys_enter")
|
||||
int test_core_flavors(void *ctx)
|
||||
{
|
||||
struct core_reloc_flavors *in_orig = (void *)&data.in;
|
||||
struct core_reloc_flavors___reversed *in_rev = (void *)&data.in;
|
||||
struct core_reloc_flavors___weird *in_weird = (void *)&data.in;
|
||||
struct core_reloc_flavors *out = (void *)&data.out;
|
||||
|
||||
/* read a using weird layout */
|
||||
if (BPF_CORE_READ(&out->a, &in_weird->a))
|
||||
return 1;
|
||||
/* read b using reversed layout */
|
||||
if (BPF_CORE_READ(&out->b, &in_rev->b))
|
||||
return 1;
|
||||
/* read c using original layout */
|
||||
if (BPF_CORE_READ(&out->c, &in_orig->c))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
44
tools/testing/selftests/bpf/progs/test_core_reloc_ints.c
Normal file
44
tools/testing/selftests/bpf/progs/test_core_reloc_ints.c
Normal file
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <stdint.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
static volatile struct data {
|
||||
char in[256];
|
||||
char out[256];
|
||||
} data;
|
||||
|
||||
struct core_reloc_ints {
|
||||
uint8_t u8_field;
|
||||
int8_t s8_field;
|
||||
uint16_t u16_field;
|
||||
int16_t s16_field;
|
||||
uint32_t u32_field;
|
||||
int32_t s32_field;
|
||||
uint64_t u64_field;
|
||||
int64_t s64_field;
|
||||
};
|
||||
|
||||
SEC("raw_tracepoint/sys_enter")
|
||||
int test_core_ints(void *ctx)
|
||||
{
|
||||
struct core_reloc_ints *in = (void *)&data.in;
|
||||
struct core_reloc_ints *out = (void *)&data.out;
|
||||
|
||||
if (BPF_CORE_READ(&out->u8_field, &in->u8_field) ||
|
||||
BPF_CORE_READ(&out->s8_field, &in->s8_field) ||
|
||||
BPF_CORE_READ(&out->u16_field, &in->u16_field) ||
|
||||
BPF_CORE_READ(&out->s16_field, &in->s16_field) ||
|
||||
BPF_CORE_READ(&out->u32_field, &in->u32_field) ||
|
||||
BPF_CORE_READ(&out->s32_field, &in->s32_field) ||
|
||||
BPF_CORE_READ(&out->u64_field, &in->u64_field) ||
|
||||
BPF_CORE_READ(&out->s64_field, &in->s64_field))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
36
tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c
Normal file
36
tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c
Normal file
@@ -0,0 +1,36 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <stdint.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
static volatile struct data {
|
||||
char in[256];
|
||||
char out[256];
|
||||
} data;
|
||||
|
||||
struct task_struct {
|
||||
int pid;
|
||||
int tgid;
|
||||
};
|
||||
|
||||
SEC("raw_tracepoint/sys_enter")
|
||||
int test_core_kernel(void *ctx)
|
||||
{
|
||||
struct task_struct *task = (void *)bpf_get_current_task();
|
||||
uint64_t pid_tgid = bpf_get_current_pid_tgid();
|
||||
int pid, tgid;
|
||||
|
||||
if (BPF_CORE_READ(&pid, &task->pid) ||
|
||||
BPF_CORE_READ(&tgid, &task->tgid))
|
||||
return 1;
|
||||
|
||||
/* validate pid + tgid matches */
|
||||
data.out[0] = (((uint64_t)pid << 32) | tgid) == pid_tgid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
57
tools/testing/selftests/bpf/progs/test_core_reloc_misc.c
Normal file
57
tools/testing/selftests/bpf/progs/test_core_reloc_misc.c
Normal file
@@ -0,0 +1,57 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <stdint.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
static volatile struct data {
|
||||
char in[256];
|
||||
char out[256];
|
||||
} data;
|
||||
|
||||
struct core_reloc_misc_output {
|
||||
int a, b, c;
|
||||
};
|
||||
|
||||
struct core_reloc_misc___a {
|
||||
int a1;
|
||||
int a2;
|
||||
};
|
||||
|
||||
struct core_reloc_misc___b {
|
||||
int b1;
|
||||
int b2;
|
||||
};
|
||||
|
||||
/* fixed two first members, can be extended with new fields */
|
||||
struct core_reloc_misc_extensible {
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
SEC("raw_tracepoint/sys_enter")
|
||||
int test_core_misc(void *ctx)
|
||||
{
|
||||
struct core_reloc_misc___a *in_a = (void *)&data.in;
|
||||
struct core_reloc_misc___b *in_b = (void *)&data.in;
|
||||
struct core_reloc_misc_extensible *in_ext = (void *)&data.in;
|
||||
struct core_reloc_misc_output *out = (void *)&data.out;
|
||||
|
||||
/* record two different relocations with the same accessor string */
|
||||
if (BPF_CORE_READ(&out->a, &in_a->a1) || /* accessor: 0:0 */
|
||||
BPF_CORE_READ(&out->b, &in_b->b1)) /* accessor: 0:0 */
|
||||
return 1;
|
||||
|
||||
/* Validate relocations capture array-only accesses for structs with
|
||||
* fixed header, but with potentially extendable tail. This will read
|
||||
* first 4 bytes of 2nd element of in_ext array of potentially
|
||||
* variably sized struct core_reloc_misc_extensible. */
|
||||
if (BPF_CORE_READ(&out->c, &in_ext[2])) /* accessor: 2 */
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
62
tools/testing/selftests/bpf/progs/test_core_reloc_mods.c
Normal file
62
tools/testing/selftests/bpf/progs/test_core_reloc_mods.c
Normal file
@@ -0,0 +1,62 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <stdint.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
static volatile struct data {
|
||||
char in[256];
|
||||
char out[256];
|
||||
} data;
|
||||
|
||||
struct core_reloc_mods_output {
|
||||
int a, b, c, d, e, f, g, h;
|
||||
};
|
||||
|
||||
typedef const int int_t;
|
||||
typedef const char *char_ptr_t;
|
||||
typedef const int arr_t[7];
|
||||
|
||||
struct core_reloc_mods_substruct {
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
} core_reloc_mods_substruct_t;
|
||||
|
||||
struct core_reloc_mods {
|
||||
int a;
|
||||
int_t b;
|
||||
char *c;
|
||||
char_ptr_t d;
|
||||
int e[3];
|
||||
arr_t f;
|
||||
struct core_reloc_mods_substruct g;
|
||||
core_reloc_mods_substruct_t h;
|
||||
};
|
||||
|
||||
SEC("raw_tracepoint/sys_enter")
|
||||
int test_core_mods(void *ctx)
|
||||
{
|
||||
struct core_reloc_mods *in = (void *)&data.in;
|
||||
struct core_reloc_mods_output *out = (void *)&data.out;
|
||||
|
||||
if (BPF_CORE_READ(&out->a, &in->a) ||
|
||||
BPF_CORE_READ(&out->b, &in->b) ||
|
||||
BPF_CORE_READ(&out->c, &in->c) ||
|
||||
BPF_CORE_READ(&out->d, &in->d) ||
|
||||
BPF_CORE_READ(&out->e, &in->e[2]) ||
|
||||
BPF_CORE_READ(&out->f, &in->f[1]) ||
|
||||
BPF_CORE_READ(&out->g, &in->g.x) ||
|
||||
BPF_CORE_READ(&out->h, &in->h.y))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
46
tools/testing/selftests/bpf/progs/test_core_reloc_nesting.c
Normal file
46
tools/testing/selftests/bpf/progs/test_core_reloc_nesting.c
Normal file
@@ -0,0 +1,46 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <stdint.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
static volatile struct data {
|
||||
char in[256];
|
||||
char out[256];
|
||||
} data;
|
||||
|
||||
struct core_reloc_nesting_substruct {
|
||||
int a;
|
||||
};
|
||||
|
||||
union core_reloc_nesting_subunion {
|
||||
int b;
|
||||
};
|
||||
|
||||
/* int a.a.a and b.b.b accesses */
|
||||
struct core_reloc_nesting {
|
||||
union {
|
||||
struct core_reloc_nesting_substruct a;
|
||||
} a;
|
||||
struct {
|
||||
union core_reloc_nesting_subunion b;
|
||||
} b;
|
||||
};
|
||||
|
||||
SEC("raw_tracepoint/sys_enter")
|
||||
int test_core_nesting(void *ctx)
|
||||
{
|
||||
struct core_reloc_nesting *in = (void *)&data.in;
|
||||
struct core_reloc_nesting *out = (void *)&data.out;
|
||||
|
||||
if (BPF_CORE_READ(&out->a.a.a, &in->a.a.a))
|
||||
return 1;
|
||||
if (BPF_CORE_READ(&out->b.b.b, &in->b.b.b))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -0,0 +1,43 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <stdint.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
static volatile struct data {
|
||||
char in[256];
|
||||
char out[256];
|
||||
} data;
|
||||
|
||||
enum core_reloc_primitives_enum {
|
||||
A = 0,
|
||||
B = 1,
|
||||
};
|
||||
|
||||
struct core_reloc_primitives {
|
||||
char a;
|
||||
int b;
|
||||
enum core_reloc_primitives_enum c;
|
||||
void *d;
|
||||
int (*f)(const char *);
|
||||
};
|
||||
|
||||
SEC("raw_tracepoint/sys_enter")
|
||||
int test_core_primitives(void *ctx)
|
||||
{
|
||||
struct core_reloc_primitives *in = (void *)&data.in;
|
||||
struct core_reloc_primitives *out = (void *)&data.out;
|
||||
|
||||
if (BPF_CORE_READ(&out->a, &in->a) ||
|
||||
BPF_CORE_READ(&out->b, &in->b) ||
|
||||
BPF_CORE_READ(&out->c, &in->c) ||
|
||||
BPF_CORE_READ(&out->d, &in->d) ||
|
||||
BPF_CORE_READ(&out->f, &in->f))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -0,0 +1,30 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <stdint.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
static volatile struct data {
|
||||
char in[256];
|
||||
char out[256];
|
||||
} data;
|
||||
|
||||
struct core_reloc_ptr_as_arr {
|
||||
int a;
|
||||
};
|
||||
|
||||
SEC("raw_tracepoint/sys_enter")
|
||||
int test_core_ptr_as_arr(void *ctx)
|
||||
{
|
||||
struct core_reloc_ptr_as_arr *in = (void *)&data.in;
|
||||
struct core_reloc_ptr_as_arr *out = (void *)&data.out;
|
||||
|
||||
if (BPF_CORE_READ(&out->a, &in[2].a))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -55,7 +55,7 @@ struct {
|
||||
__type(value, raw_stack_trace_t);
|
||||
} rawdata_map SEC(".maps");
|
||||
|
||||
SEC("tracepoint/raw_syscalls/sys_enter")
|
||||
SEC("raw_tracepoint/sys_enter")
|
||||
int bpf_prog1(void *ctx)
|
||||
{
|
||||
int max_len, max_buildid_len, usize, ksize, total_size;
|
||||
|
@@ -19,10 +19,29 @@
|
||||
struct bpf_map_def SEC("maps") results = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(__u32),
|
||||
.value_size = sizeof(__u64),
|
||||
.max_entries = 1,
|
||||
.value_size = sizeof(__u32),
|
||||
.max_entries = 3,
|
||||
};
|
||||
|
||||
static __always_inline __s64 gen_syncookie(void *data_end, struct bpf_sock *sk,
|
||||
void *iph, __u32 ip_size,
|
||||
struct tcphdr *tcph)
|
||||
{
|
||||
__u32 thlen = tcph->doff * 4;
|
||||
|
||||
if (tcph->syn && !tcph->ack) {
|
||||
// packet should only have an MSS option
|
||||
if (thlen != 24)
|
||||
return 0;
|
||||
|
||||
if ((void *)tcph + thlen > data_end)
|
||||
return 0;
|
||||
|
||||
return bpf_tcp_gen_syncookie(sk, iph, ip_size, tcph, thlen);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __always_inline void check_syncookie(void *ctx, void *data,
|
||||
void *data_end)
|
||||
{
|
||||
@@ -33,8 +52,10 @@ static __always_inline void check_syncookie(void *ctx, void *data,
|
||||
struct ipv6hdr *ipv6h;
|
||||
struct tcphdr *tcph;
|
||||
int ret;
|
||||
__u32 key_mss = 2;
|
||||
__u32 key_gen = 1;
|
||||
__u32 key = 0;
|
||||
__u64 value = 1;
|
||||
__s64 seq_mss;
|
||||
|
||||
ethh = data;
|
||||
if (ethh + 1 > data_end)
|
||||
@@ -66,6 +87,9 @@ static __always_inline void check_syncookie(void *ctx, void *data,
|
||||
if (sk->state != BPF_TCP_LISTEN)
|
||||
goto release;
|
||||
|
||||
seq_mss = gen_syncookie(data_end, sk, ipv4h, sizeof(*ipv4h),
|
||||
tcph);
|
||||
|
||||
ret = bpf_tcp_check_syncookie(sk, ipv4h, sizeof(*ipv4h),
|
||||
tcph, sizeof(*tcph));
|
||||
break;
|
||||
@@ -95,6 +119,9 @@ static __always_inline void check_syncookie(void *ctx, void *data,
|
||||
if (sk->state != BPF_TCP_LISTEN)
|
||||
goto release;
|
||||
|
||||
seq_mss = gen_syncookie(data_end, sk, ipv6h, sizeof(*ipv6h),
|
||||
tcph);
|
||||
|
||||
ret = bpf_tcp_check_syncookie(sk, ipv6h, sizeof(*ipv6h),
|
||||
tcph, sizeof(*tcph));
|
||||
break;
|
||||
@@ -103,8 +130,19 @@ static __always_inline void check_syncookie(void *ctx, void *data,
|
||||
return;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
bpf_map_update_elem(&results, &key, &value, 0);
|
||||
if (seq_mss > 0) {
|
||||
__u32 cookie = (__u32)seq_mss;
|
||||
__u32 mss = seq_mss >> 32;
|
||||
|
||||
bpf_map_update_elem(&results, &key_gen, &cookie, 0);
|
||||
bpf_map_update_elem(&results, &key_mss, &mss, 0);
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
__u32 cookie = bpf_ntohl(tcph->ack_seq) - 1;
|
||||
|
||||
bpf_map_update_elem(&results, &key, &cookie, 0);
|
||||
}
|
||||
|
||||
release:
|
||||
bpf_sk_release(sk);
|
||||
|
Reference in New Issue
Block a user