From b20f7446626a16c8fa7d56abec026e93244000a5 Mon Sep 17 00:00:00 2001
From: Eugene Syromyatnikov <evgsyr@gmail.com>
Date: Mon, 5 Mar 2018 15:53:08 +0100
Subject: [PATCH] bpf: improve handling of various sizes of BPF_MAP_CREATE
 attributes

* bpf.c (BEGIN_BPF_CMD_DECODER(BPF_MAP_CREATE)): Skip printing
the rest of the structure if len is less than the offset of the end
of max_entries, map_flags, or inner_map_fd field.
* tests/bpf.c (BPF_MAP_CREATE_checks): Add two more checks.
---
 bpf.c       | 15 +++++++++++++++
 tests/bpf.c | 37 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/bpf.c b/bpf.c
index 8d694240..60b55d16 100644
--- a/bpf.c
+++ b/bpf.c
@@ -133,8 +133,23 @@ BEGIN_BPF_CMD_DECODER(BPF_MAP_CREATE)
 	PRINT_FIELD_U(", ", attr, key_size);
 	PRINT_FIELD_U(", ", attr, value_size);
 	PRINT_FIELD_U(", ", attr, max_entries);
+
+	/* map_flags field was added in Linux commit v4.6-rc1~91^2~108^2~6. */
+	if (len <= offsetof(struct BPF_MAP_CREATE_struct, map_flags))
+		break;
 	PRINT_FIELD_FLAGS(", ", attr, map_flags, bpf_map_flags, "BPF_F_???");
+
+	/*
+	 * inner_map_fd field was added in Linux commit
+	 * v4.12-rc1~64^3~373^2~2.
+	 */
+	if (len <= offsetof(struct BPF_MAP_CREATE_struct, inner_map_fd))
+		break;
 	PRINT_FIELD_FD(", ", attr, inner_map_fd, tcp);
+
+	/* numa_node field was added in Linux commit v4.14-rc1~130^2~196^2~1. */
+	if (len <= offsetof(struct BPF_MAP_CREATE_struct, numa_node))
+		break;
 	if (attr.map_flags & BPF_F_NUMA_NODE) {
 		/*
 		 * Kernel uses the value of -1 as a designation for "no NUMA
diff --git a/tests/bpf.c b/tests/bpf.c
index 59044512..7dd4ba4a 100644
--- a/tests/bpf.c
+++ b/tests/bpf.c
@@ -238,7 +238,7 @@ static const struct bpf_attr_check BPF_MAP_CREATE_checks[] = {
 		.data = { .BPF_MAP_CREATE_data = { .map_type = 2 } },
 		.size = offsetofend(struct BPF_MAP_CREATE_struct, map_type),
 		.str = "map_type=BPF_MAP_TYPE_ARRAY, key_size=0, value_size=0"
-		       ", max_entries=0, map_flags=0, inner_map_fd=0"
+		       ", max_entries=0"
 	},
 	{ /* 1 */
 		.data = { .BPF_MAP_CREATE_data = {
@@ -275,6 +275,41 @@ static const struct bpf_attr_check BPF_MAP_CREATE_checks[] = {
 		       ", inner_map_fd=-1576685468",
 	},
 	{ /* 3 */
+		.data = { .BPF_MAP_CREATE_data = {
+			.map_type = 0xdeadf00d,
+			.key_size = 0xface1e55,
+			.value_size = 0xbadc0ded,
+			.max_entries = 0xbeefcafe,
+			.map_flags = 0xc0dedead,
+			.inner_map_fd = 2718281828,
+			.numa_node = -1,
+		} },
+		.size = offsetofend(struct BPF_MAP_CREATE_struct, map_flags),
+		.str = "map_type=0xdeadf00d /* BPF_MAP_TYPE_??? */"
+		       ", key_size=4207812181, value_size=3134983661"
+		       ", max_entries=3203386110"
+		       ", map_flags=BPF_F_NO_PREALLOC|BPF_F_NUMA_NODE"
+				   "|0xc0dedea8",
+	},
+	{ /* 4 */
+		.data = { .BPF_MAP_CREATE_data = {
+			.map_type = 0xdeadf00d,
+			.key_size = 0xface1e55,
+			.value_size = 0xbadc0ded,
+			.max_entries = 0xbeefcafe,
+			.map_flags = 0xc0dedead,
+			.inner_map_fd = 2718281828,
+			.numa_node = -1,
+		} },
+		.size = offsetofend(struct BPF_MAP_CREATE_struct, inner_map_fd),
+		.str = "map_type=0xdeadf00d /* BPF_MAP_TYPE_??? */"
+		       ", key_size=4207812181, value_size=3134983661"
+		       ", max_entries=3203386110"
+		       ", map_flags=BPF_F_NO_PREALLOC|BPF_F_NUMA_NODE"
+				   "|0xc0dedea8"
+		       ", inner_map_fd=-1576685468",
+	},
+	{ /* 5 */
 		.data = { .BPF_MAP_CREATE_data = {
 			.map_type = 0xdeadf00d,
 			.key_size = 0xface1e55,
-- 
2.40.0