summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Syromyatnikov <evgsyr@gmail.com>2022-05-25 17:34:20 +0200
committerDmitry V. Levin <ldv@strace.io>2022-05-26 23:11:20 +0000
commitdda44d34e5fc0878e6ba3e08c6f297522758bae6 (patch)
tree0843db580794ab05f44a529d350f59775301802d
parentc3ae37c314bfb43d5646699136debf96a5ed3540 (diff)
downloadstrace-dda44d34e5fc0878e6ba3e08c6f297522758bae6.tar.gz
bpf: improve bpf(BPF_LINK_CREATE) decoding
union bpf_attr.link_create got a couple of new fields; this patch attempts to decode it based on the attach_type field value, which is imprecise, but the next best thing without information about the type of prog_fd. * src/xlat/bpf_link_create_kprobe_multi_flags.in: New file. * src/gen_bpf_attr_check.sh: Ignore anonymous union fields; * src/bpf_attr.h (BPF_LINK_CREATE_struct): Add target_btf_id, iter_info, iter_info_len, perf_event.bpf_cookie, kprobe_multi.flags, kprobe_multi.cnt, kprobe_multi.syms, kprobe_multi.addrs, kprobe_multi.cookies fields. (expected_BPF_LINK_CREATE_struct_size): Change to 48. * src/bpf.c: Include "xlat/bpf_link_create_kprobe_multi_flags.h". (BEGIN_BPF_CMD_DECODER): Remove const qualifier from attr_size definition. (union strace_bpf_iter_link_info): New type definition. (print_iter_info_array_member, print_str_array_member): New functions. (BEGIN_BPF_CMD_DECODER(BPF_LINK_CREATE)): Decode new fields. * tests/bpf.c: Add new checks.
-rw-r--r--src/bpf.c137
-rw-r--r--src/bpf_attr.h22
-rwxr-xr-xsrc/gen_bpf_attr_check.sh2
-rw-r--r--src/xlat/bpf_link_create_kprobe_multi_flags.in1
-rw-r--r--tests/bpf.c309
5 files changed, 458 insertions, 13 deletions
diff --git a/src/bpf.c b/src/bpf.c
index 2fef61686..ab17401c5 100644
--- a/src/bpf.c
+++ b/src/bpf.c
@@ -29,6 +29,7 @@
#include "xlat/bpf_query_flags.h"
#include "xlat/bpf_task_fd_type.h"
#include "xlat/bpf_test_run_flags.h"
+#include "xlat/bpf_link_create_kprobe_multi_flags.h"
#include "xlat/ebpf_regs.h"
#include "xlat/numa_node.h"
@@ -48,7 +49,7 @@ bpf_cmd_decoder(struct tcb *const tcp, \
static DECL_BPF_CMD_DECODER(decode_ ## bpf_cmd) \
{ \
struct bpf_cmd ## _struct attr = {}; \
- const size_t attr_size = bpf_cmd ## _struct_size; \
+ size_t attr_size = bpf_cmd ## _struct_size; \
const unsigned int len = MIN(size, attr_size); \
memcpy(&attr, data, len); \
do { \
@@ -1367,6 +1368,41 @@ BEGIN_BPF_CMD_DECODER(BPF_MAP_DELETE_BATCH)
}
END_BPF_CMD_DECODER(0)
+union strace_bpf_iter_link_info {
+ struct {
+ uint32_t map_fd;
+ } map;
+};
+
+static bool
+print_iter_info_array_member(struct tcb *tcp, void *elem_buf,
+ size_t elem_size, void *data)
+{
+ union strace_bpf_iter_link_info *bili =
+ (union strace_bpf_iter_link_info *) elem_buf;
+
+ tprint_struct_begin();
+ tprints_field_name("map");
+ tprint_struct_begin();
+ PRINT_FIELD_FD(bili->map, map_fd, tcp);
+ tprint_struct_end();
+ tprint_struct_end();
+
+ return true;
+}
+
+static bool
+print_str_array_member(struct tcb *tcp, void *elem_buf,
+ size_t elem_size, void *data)
+{
+ kernel_ulong_t ptr = opt_wordsize(*(uint64_t *) elem_buf,
+ *(uint32_t *) elem_buf);
+
+ printstr(tcp, ptr);
+
+ return true;
+}
+
BEGIN_BPF_CMD_DECODER(BPF_LINK_CREATE)
{
tprint_struct_begin();
@@ -1379,6 +1415,105 @@ BEGIN_BPF_CMD_DECODER(BPF_LINK_CREATE)
PRINT_FIELD_XVAL(attr, attach_type, bpf_attach_type, "BPF_???");
tprint_struct_next();
PRINT_FIELD_X(attr, flags);
+
+ if (len <= offsetof(struct BPF_LINK_CREATE_struct, target_btf_id))
+ goto print_bpf_link_create_end;
+
+ /* Trying to guess the union decoding based on the attach type */
+ switch (attr.attach_type) {
+ /* TODO: check that prog type == BPF_PROG_TYPE_EXT */
+ /*
+ * Yes, it is BPF_CGROUP_INET_INGRESS, see the inconceivable genius
+ * of the expected_attach_type check in v5.6-rc1~151^2~46^2~1^2~2.
+ */
+ case 0:
+ /* Introduced in Linux commit v5.10-rc1~107^2~96^2~12^2~5 */
+ if (attr.target_btf_id) {
+ tprint_struct_next();
+ PRINT_FIELD_U(attr, target_btf_id);
+ }
+ attr_size = offsetofend(typeof(attr), target_btf_id);
+ break;
+
+ /* TODO: prog type == BPF_PROG_TYPE_TRACING */
+ case BPF_TRACE_ITER: {
+ /* Introduced in Linux commit v5.9-rc1~36^2~30^2~8^2~1 */
+ union strace_bpf_iter_link_info buf;
+
+ tprint_struct_next();
+ tprints_field_name("iter_info");
+ print_big_u64_addr(attr.iter_info);
+ print_array(tcp, attr.iter_info, attr.iter_info_len,
+ &buf, sizeof(buf), tfetch_mem,
+ print_iter_info_array_member, 0);
+ tprint_struct_next();
+ PRINT_FIELD_U(attr, iter_info_len);
+ attr_size = offsetofend(typeof(attr), iter_info_len);
+ break;
+ }
+
+ /* TODO: prog type == BPF_PROG_TYPE_{KPROBE,PERF_EVENT,TRACEPOINT} */
+ case BPF_PERF_EVENT:
+ /* Introduced in Linux commit v5.15-rc1~157^2~22^2~33^2~11 */
+ tprint_struct_next();
+ tprints_field_name("perf_event");
+ tprint_struct_begin();
+ PRINT_FIELD_X(attr.perf_event, bpf_cookie);
+ tprint_struct_end();
+ attr_size = offsetofend(typeof(attr), perf_event.bpf_cookie);
+ break;
+
+ /* TODO: prog type == BPF_PROG_TYPE_KPROBE */
+ case BPF_TRACE_KPROBE_MULTI: {
+ /* Introduced in Linux commit v5.18-rc1~136^2~11^2~28^2~10 */
+ union {
+ kernel_ulong_t ptr;
+ uint64_t addr;
+ uint64_t cookie;
+ } buf;
+
+ tprint_struct_next();
+ tprints_field_name("kprobe_multi");
+ tprint_struct_begin();
+ PRINT_FIELD_FLAGS(attr.kprobe_multi, flags,
+ bpf_link_create_kprobe_multi_flags,
+ "BPF_F_???");
+ tprint_struct_next();
+ PRINT_FIELD_U(attr.kprobe_multi, cnt);
+ tprint_struct_next();
+ tprints_field_name("syms");
+ print_big_u64_addr(attr.kprobe_multi.syms);
+ print_array(tcp, attr.kprobe_multi.syms, attr.kprobe_multi.cnt,
+ &buf.ptr, current_wordsize,
+ tfetch_mem, print_str_array_member, 0);
+ tprint_struct_next();
+ tprints_field_name("addrs");
+ print_big_u64_addr(attr.kprobe_multi.addrs);
+ print_array(tcp, attr.kprobe_multi.addrs, attr.kprobe_multi.cnt,
+ &buf.ptr, sizeof(buf.addr),
+ tfetch_mem, print_xint_array_member, 0);
+ tprint_struct_next();
+ tprints_field_name("cookies");
+ print_big_u64_addr(attr.kprobe_multi.cookies);
+ print_array(tcp, attr.kprobe_multi.cookies,
+ attr.kprobe_multi.cnt,
+ &buf.cookie, sizeof(buf.cookie),
+ tfetch_mem, print_xint_array_member, 0);
+ tprint_struct_end();
+ attr_size = offsetofend(typeof(attr), kprobe_multi.cookies);
+ break;
+ }
+
+ default:
+ /*
+ * NB: resetting attr_size, so decode_attr_extra_data
+ * can pick up non-zero values in the union at the end
+ * of the link_create struct.
+ */
+ attr_size = offsetofend(typeof(attr), flags);
+ }
+
+print_bpf_link_create_end:
tprint_struct_end();
}
END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD)
diff --git a/src/bpf_attr.h b/src/bpf_attr.h
index 7f853e264..62d7bd76f 100644
--- a/src/bpf_attr.h
+++ b/src/bpf_attr.h
@@ -401,11 +401,31 @@ struct BPF_LINK_CREATE_struct /* link_create */ {
uint32_t target_fd;
uint32_t attach_type;
uint32_t flags;
+ union {
+ uint32_t target_btf_id;
+
+ struct {
+ uint64_t ATTRIBUTE_ALIGNED(8) iter_info;
+ uint32_t iter_info_len;
+ };
+
+ struct {
+ uint64_t ATTRIBUTE_ALIGNED(8) bpf_cookie;
+ } perf_event;
+
+ struct {
+ uint32_t flags;
+ uint32_t cnt;
+ uint64_t ATTRIBUTE_ALIGNED(8) syms;
+ uint64_t ATTRIBUTE_ALIGNED(8) addrs;
+ uint64_t ATTRIBUTE_ALIGNED(8) cookies;
+ } kprobe_multi;
+ };
};
# define BPF_LINK_CREATE_struct_size \
sizeof(struct BPF_LINK_CREATE_struct)
-# define expected_BPF_LINK_CREATE_struct_size 16
+# define expected_BPF_LINK_CREATE_struct_size 48
struct BPF_LINK_UPDATE_struct /* link_update */ {
uint32_t link_fd;
diff --git a/src/gen_bpf_attr_check.sh b/src/gen_bpf_attr_check.sh
index c8fe1e3e6..b8c2cdb40 100755
--- a/src/gen_bpf_attr_check.sh
+++ b/src/gen_bpf_attr_check.sh
@@ -32,7 +32,7 @@ for struct in $(sed -n 's/^struct \([^[:space:]]\+_struct\) .*/\1/p' < "$input")
enum="$enum${enum:+.}"
ENUM="$ENUM${ENUM:+_}"
sed -n '/^struct '"$struct"' [^{]*{/,/^};$/p' < "$input" |
- sed -n 's/^[[:space:]]\+[^][;:]*[[:space:]]\([^][[:space:];:]\+\)\(\[[^;:]*\]\)\?;$/\1/p' |
+ sed -n 's/^[[:space:]]\+[^][;:]*[[:space:]]\([^]}[[:space:];:]\+\)\(\[[^;:]*\]\)\?;$/\1/p' |
while read field; do
FIELD="$(printf %s "$field" |tr '[:lower:]' '[:upper:]')"
cat <<EOF
diff --git a/src/xlat/bpf_link_create_kprobe_multi_flags.in b/src/xlat/bpf_link_create_kprobe_multi_flags.in
new file mode 100644
index 000000000..c65157d99
--- /dev/null
+++ b/src/xlat/bpf_link_create_kprobe_multi_flags.in
@@ -0,0 +1 @@
+BPF_F_KPROBE_MULTI_RETURN (1U << 0)
diff --git a/tests/bpf.c b/tests/bpf.c
index e4ffac3bb..8668575be 100644
--- a/tests/bpf.c
+++ b/tests/bpf.c
@@ -26,6 +26,7 @@
#include "print_fields.h"
#include "xlat.h"
+#include "xlat/bpf_attach_type.h"
#include "xlat/bpf_commands.h"
#include "xlat/bpf_map_types.h"
#include "xlat/bpf_prog_types.h"
@@ -1484,24 +1485,312 @@ static const struct bpf_attr_check BPF_MAP_DELETE_BATCH_checks[] = {
}
};
-static const struct bpf_attr_check BPF_LINK_CREATE_checks[] = {
- {
- .data = { .BPF_LINK_CREATE_data = { .prog_fd = -1, .target_fd = -2 } },
- .size = offsetofend(struct BPF_LINK_CREATE_struct, flags),
- .str = "link_create={prog_fd=-1, target_fd=-2"
+static void
+init_BPF_LINK_CREATE_attr1(struct bpf_attr_check *check, size_t idx)
+{
+ struct BPF_LINK_CREATE_struct *attr = &check->data.BPF_LINK_CREATE_data;
+
+ attr->attach_type = idx;
+}
+
+static void
+print_BPF_LINK_CREATE_attr1(const struct bpf_attr_check *check,
+ unsigned long addr, size_t idx)
+{
+ printf("link_create={prog_fd=-1, target_fd=-559038737"
+ ", attach_type=%s, flags=0x4}",
+ sprintxval(bpf_attach_type, idx, "BPF_???"));
+}
+
+/* Keep sorted */
+static const uint8_t special_attach_types[] =
+ { 0, BPF_TRACE_ITER, BPF_PERF_EVENT, BPF_TRACE_KPROBE_MULTI };
+
+static void
+init_BPF_LINK_CREATE_attr2(struct bpf_attr_check *check, size_t idx)
+{
+ struct BPF_LINK_CREATE_struct *attr = &check->data.BPF_LINK_CREATE_data;
+
+ /* skip special_attach_types */
+ for (size_t i = 0; i < ARRAY_SIZE(special_attach_types)
+ && idx >= special_attach_types[i]; i++, idx++);
+
+ attr->attach_type = idx;
+
+ check->data.char_data[19] = ' ';
+ check->data.char_data[23] = 'O';
+ check->data.char_data[27] = 'H';
+ check->data.char_data[31] = ' ';
+ check->data.char_data[35] = 'H';
+ check->data.char_data[39] = 'A';
+ check->data.char_data[43] = 'I';
+ check->data.char_data[47] = '!';
+}
+
+static void
+print_BPF_LINK_CREATE_attr2(const struct bpf_attr_check *check,
+ unsigned long addr, size_t idx)
+{
+ /* skip special_attach_types */
+ for (size_t i = 0; i < ARRAY_SIZE(special_attach_types)
+ && idx >= special_attach_types[i]; i++, idx++);
+
+ printf("link_create={prog_fd=-1, target_fd=-559038737"
+ ", attach_type=%s, flags=0xbadc0ded}, "
+#if VERBOSE
+ "extra_data=\"\\x00\\x00\\x00\\x20\\x00\\x00\\x00\\x4f"
+ "\\x00\\x00\\x00\\x48\\x00\\x00\\x00\\x20\\x00\\x00\\x00\\x48"
+ "\\x00\\x00\\x00\\x41\\x00\\x00\\x00\\x49\\x00\\x00\\x00\\x21\""
+ " /* bytes 16..47 */"
+#else
+ "..."
+#endif
+ ,
+ sprintxval(bpf_attach_type, idx, "BPF_???"));
+}
+
+static const int iter_info_data[] = { 0, 42, 314159265, 0xbadc0ded, -1 };
+static int *iter_info_data_p;
+
+static void
+init_BPF_LINK_CREATE_attr7(struct bpf_attr_check *check, size_t idx)
+{
+ struct BPF_LINK_CREATE_struct *attr = &check->data.BPF_LINK_CREATE_data;
+
+ if (!iter_info_data_p) {
+ iter_info_data_p = tail_memdup(iter_info_data,
+ sizeof(iter_info_data));
+ }
+
+ attr->iter_info = (uintptr_t) iter_info_data_p;
+ attr->iter_info_len = ARRAY_SIZE(iter_info_data) + idx;
+}
+
+static void
+print_BPF_LINK_CREATE_attr7(const struct bpf_attr_check *check,
+ unsigned long addr, size_t idx)
+{
+ printf("link_create={prog_fd=0" FD0_PATH ", target_fd=0" FD0_PATH
+ ", attach_type=BPF_TRACE_ITER, flags=0"
+ ", iter_info=[{map={map_fd=0" FD0_PATH "}}, {map={map_fd=42}}"
+ ", {map={map_fd=314159265}}, {map={map_fd=-1159983635}}"
+ ", {map={map_fd=-1}}");
+ if (idx) {
+ printf(", ... /* %p */",
+ iter_info_data_p + ARRAY_SIZE(iter_info_data));
+ }
+ printf("], iter_info_len=%zu}", ARRAY_SIZE(iter_info_data) + idx);
+
+}
+
+static const char *syms_data[] = { "foo", NULL, "OH\0HAI",
+ "abcdefghijklmnopqrstuvwxyz0123456789" };
+static char **syms_data_p;
+static const uint64_t addrs_data[] = { 0, 1, 0xbadc0ded,
+ 0xfacefeeddeadc0deULL };
+static uint64_t *addrs_data_p;
+
+static_assert(ARRAY_SIZE(syms_data) == ARRAY_SIZE(addrs_data),
+ "syms_data and addrs_data have to have the same element count");
+
+static void
+init_BPF_LINK_CREATE_attr12(struct bpf_attr_check *check, size_t idx)
+{
+ struct BPF_LINK_CREATE_struct *attr = &check->data.BPF_LINK_CREATE_data;
+
+ if (!syms_data_p)
+ syms_data_p = tail_memdup(syms_data, sizeof(syms_data));
+ if (!addrs_data_p)
+ addrs_data_p = tail_memdup(addrs_data, sizeof(addrs_data));
+
+ attr->kprobe_multi.cnt = ARRAY_SIZE(syms_data) + idx;
+ attr->kprobe_multi.syms = (uintptr_t) syms_data_p;
+ attr->kprobe_multi.addrs = (uintptr_t) addrs_data_p;
+ attr->kprobe_multi.cookies = (uintptr_t) addrs_data_p;
+}
+
+static void
+print_BPF_LINK_CREATE_attr12(const struct bpf_attr_check *check,
+ unsigned long addr, size_t idx)
+{
+ printf("link_create={prog_fd=0" FD0_PATH ", target_fd=0" FD0_PATH
+ ", attach_type=BPF_TRACE_KPROBE_MULTI, flags=0"
+ ", kprobe_multi={flags=BPF_F_KPROBE_MULTI_RETURN|0xfacebeee"
+ ", cnt=%zu", ARRAY_SIZE(syms_data) + idx);
+ printf(", syms=[\"foo\", NULL, \"OH\""
+ ", \"abcdefghijklmnopqrstuvwxyz012345\"...");
+ if (idx)
+ printf(", ... /* %p */", syms_data_p + ARRAY_SIZE(syms_data));
+ for (size_t i = 0; i < 2; i++) {
+ printf("], %s=[0, 0x1, 0xbadc0ded, 0xfacefeeddeadc0de",
+ i ? "cookies" : "addrs");
+ if (idx) {
+ printf(", ... /* %p */",
+ addrs_data_p + ARRAY_SIZE(addrs_data));
+ }
+ }
+ printf("]}}");
+}
+
+static struct bpf_attr_check BPF_LINK_CREATE_checks[] = {
+ { /* 0 */
+ .data = { .BPF_LINK_CREATE_data = { .prog_fd = 0, .target_fd = 0 } },
+ .size = offsetofend(struct BPF_LINK_CREATE_struct, target_fd),
+ .str = "link_create={prog_fd=0" FD0_PATH ", target_fd=0" FD0_PATH
", attach_type=BPF_CGROUP_INET_INGRESS, flags=0}"
},
- {
+ { /* 1 */
.data = { .BPF_LINK_CREATE_data = {
.prog_fd = -1,
.target_fd = 0xdeadbeef,
- .attach_type = 5,
.flags = 4
} },
.size = offsetofend(struct BPF_LINK_CREATE_struct, flags),
- .str = "link_create={prog_fd=-1, target_fd=-559038737"
- ", attach_type=BPF_SK_SKB_STREAM_VERDICT, flags=0x4}"
- }
+ .iters = ARRAY_SIZE(bpf_attach_type_xdata),
+ .init_fn = init_BPF_LINK_CREATE_attr1,
+ .print_fn = print_BPF_LINK_CREATE_attr1,
+ },
+ { /* 2 - all non-special attach_types */
+ .data = { .BPF_LINK_CREATE_data = {
+ .prog_fd = -1,
+ .target_fd = 0xdeadbeef,
+ .attach_type = 5,
+ .flags = 0xbadc0ded
+ } },
+ .size = 48,
+ .iters = ARRAY_SIZE(bpf_attach_type_xdata)
+ - ARRAY_SIZE(special_attach_types),
+ .init_fn = init_BPF_LINK_CREATE_attr2,
+ .print_fn = print_BPF_LINK_CREATE_attr2,
+ },
+
+ { /* 3 */
+ .data = { .BPF_LINK_CREATE_data = {
+ .attach_type = 0,
+ } },
+ .size = offsetofend(struct BPF_LINK_CREATE_struct,
+ target_btf_id),
+ .str = "link_create={prog_fd=0" FD0_PATH", target_fd=0" FD0_PATH
+ ", attach_type=BPF_CGROUP_INET_INGRESS, flags=0}"
+ },
+ { /* 4 */
+ .data = { .BPF_LINK_CREATE_data = {
+ .attach_type = 0,
+ .target_btf_id = 0xfacefeed,
+ } },
+ .size = offsetofend(struct BPF_LINK_CREATE_struct,
+ target_btf_id),
+ .str = "link_create={prog_fd=0" FD0_PATH", target_fd=0" FD0_PATH
+ ", attach_type=BPF_CGROUP_INET_INGRESS, flags=0"
+ ", target_btf_id=4207869677}"
+ },
+
+ { /* 5 */
+ .data = { .BPF_LINK_CREATE_data = {
+ .attach_type = 28,
+ } },
+ .size = offsetofend(struct BPF_LINK_CREATE_struct,
+ iter_info_len),
+ .str = "link_create={prog_fd=0" FD0_PATH", target_fd=0" FD0_PATH
+ ", attach_type=BPF_TRACE_ITER, flags=0"
+ ", iter_info=NULL, iter_info_len=0}"
+ },
+ { /* 6 */
+ .data = { .BPF_LINK_CREATE_data = {
+ .attach_type = 28,
+ .iter_info = 0xffffffff00000000,
+ .iter_info_len = 0xdeadface,
+ } },
+ .size = offsetofend(struct BPF_LINK_CREATE_struct,
+ iter_info_len),
+ .str = "link_create={prog_fd=0" FD0_PATH", target_fd=0" FD0_PATH
+ ", attach_type=BPF_TRACE_ITER, flags=0"
+ ", iter_info=" BIG_ADDR("0xffffffff00000000", "NULL")
+ ", iter_info_len=3735943886}"
+ },
+ { /* 7 */
+ .data = { .BPF_LINK_CREATE_data = {
+ .attach_type = 28,
+ } },
+ .size = offsetofend(struct BPF_LINK_CREATE_struct,
+ iter_info_len),
+ .iters = 2,
+ .init_fn = init_BPF_LINK_CREATE_attr7,
+ .print_fn = print_BPF_LINK_CREATE_attr7,
+ },
+
+ { /* 8 */
+ .data = { .BPF_LINK_CREATE_data = {
+ .attach_type = 41,
+ } },
+ .size = offsetofend(struct BPF_LINK_CREATE_struct,
+ perf_event.bpf_cookie),
+ .str = "link_create={prog_fd=0" FD0_PATH", target_fd=0" FD0_PATH
+ ", attach_type=BPF_PERF_EVENT, flags=0"
+ ", perf_event={bpf_cookie=0}}"
+ },
+ { /* 9 */
+ .data = { .BPF_LINK_CREATE_data = {
+ .attach_type = 41,
+ .perf_event = { .bpf_cookie = 0xdeadc0defacecafeULL },
+ } },
+ .size = offsetofend(struct BPF_LINK_CREATE_struct,
+ perf_event.bpf_cookie),
+ .str = "link_create={prog_fd=0" FD0_PATH", target_fd=0" FD0_PATH
+ ", attach_type=BPF_PERF_EVENT, flags=0"
+ ", perf_event={bpf_cookie=0xdeadc0defacecafe}}"
+ },
+
+ { /* 10 */
+ .data = { .BPF_LINK_CREATE_data = {
+ .attach_type = 42,
+ } },
+ .size = offsetofend(struct BPF_LINK_CREATE_struct,
+ kprobe_multi.cookies),
+ .str = "link_create={prog_fd=0" FD0_PATH", target_fd=0" FD0_PATH
+ ", attach_type=BPF_TRACE_KPROBE_MULTI, flags=0"
+ ", kprobe_multi={flags=0, cnt=0, syms=NULL, addrs=NULL"
+ ", cookies=NULL}}"
+ },
+ { /* 11 */
+ .data = { .BPF_LINK_CREATE_data = {
+ .attach_type = 42,
+ .kprobe_multi = {
+ .flags = 0xdeadc0de,
+ .cnt = 0xbadfaced,
+ .syms = 0xffffffff00000000,
+ .addrs = 0xffffffff00000000,
+ .cookies = 0xffffffff00000000,
+ },
+ } },
+ .size = offsetofend(struct BPF_LINK_CREATE_struct,
+ kprobe_multi.cookies),
+ .str = "link_create={prog_fd=0" FD0_PATH", target_fd=0" FD0_PATH
+ ", attach_type=BPF_TRACE_KPROBE_MULTI, flags=0"
+ ", kprobe_multi={flags=0xdeadc0de /* BPF_F_??? */"
+ ", cnt=3135220973"
+ ", syms=" BIG_ADDR("0xffffffff00000000", "NULL")
+ ", addrs=" BIG_ADDR("0xffffffff00000000", "NULL")
+ ", cookies=" BIG_ADDR("0xffffffff00000000", "NULL") "}}"
+ },
+ /*
+ * Note that here we rely on the fact that this attach_type has the
+ * largest de-facto attr_size to get the additional checks performed
+ * with the last check passed.
+ */
+ { /* 12 */
+ .data = { .BPF_LINK_CREATE_data = {
+ .attach_type = 42,
+ .kprobe_multi = {
+ .flags = 0xfacebeef,
+ }
+ } },
+ .size = offsetofend(struct BPF_LINK_CREATE_struct,
+ kprobe_multi.cookies),
+ .iters = 2,
+ .init_fn = init_BPF_LINK_CREATE_attr12,
+ .print_fn = print_BPF_LINK_CREATE_attr12,
+ },
};
static const struct bpf_attr_check BPF_LINK_UPDATE_checks[] = {