support per-map/prog selinux context and cross .o map sharing

Tested by making the map struct conditional on #define V18,
and only #defining that in the top line of netd.c,
this results in:

$ objdump -s -j size_of_bpf_map_def out/target/product/vsoc_x86_64/apex/com.android.tethering/etc/bpf/net_shared/clatd.o
out/target/product/vsoc_x86_64/apex/com.android.tethering/etc/bpf/net_shared/clatd.o:     file format elf64-little
Contents of section size_of_bpf_map_def:
 0000 30000000 00000000                    0.......

$ objdump -s -j size_of_bpf_prog_def out/target/product/vsoc_x86_64/apex/com.android.tethering/etc/bpf/net_shared/clatd.o
out/target/product/vsoc_x86_64/apex/com.android.tethering/etc/bpf/net_shared/clatd.o:     file format elf64-little
Contents of section size_of_bpf_prog_def:
 0000 1c000000 00000000                    ........

$ objdump -s -j size_of_bpf_map_def out/target/product/vsoc_x86_64/apex/com.android.tethering/etc/bpf/netd_shared/netd.o
out/target/product/vsoc_x86_64/apex/com.android.tethering/etc/bpf/netd_shared/netd.o:     file format elf64-little
Contents of section size_of_bpf_map_def:
 0000 74000000 00000000                    t.......

$ objdump -s -j size_of_bpf_prog_def out/target/product/vsoc_x86_64/apex/com.android.tethering/etc/bpf/netd_shared/netd.o
out/target/product/vsoc_x86_64/apex/com.android.tethering/etc/bpf/netd_shared/netd.o:     file format elf64-little
Contents of section size_of_bpf_prog_def:
 0000 5c000000 00000000                    \.......

$ echo $[0x00000030] $[0x00000074]
48 116

$ echo $[0x0000001c] $[0x0000005c]
28 92

and it still successfully boots.
So the struct extension infrastructure works as desired.

Bug: 218408035
Test: TreeHugger
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I8b55769e69dbf9580e844f2a50d48651fd9a0cff
diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h
index 1371668..8bad98a 100644
--- a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h
+++ b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h
@@ -111,6 +111,15 @@
 // BPF wants 8, but 32-bit x86 wants 4
 //_Static_assert(_Alignof(unsigned long long) == 8, "_Alignof unsigned long long != 8");
 
+// Length of strings (incl. selinux_context and pin_subdir)
+// in the bpf_map_def and bpf_prog_def structs.
+//
+// WARNING: YOU CANNOT *EVER* CHANGE THESE
+// as this would affect the structure size in backwards incompatible ways
+// and break mainline module loading on older Android T devices
+#define BPF_SELINUX_CONTEXT_CHAR_ARRAY_SIZE 32
+#define BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE 32
+
 /*
  * Map structure to be used by Android eBPF C programs. The Android eBPF loader
  * uses this structure from eBPF object to create maps at boot time.
@@ -142,14 +151,41 @@
     unsigned int bpfloader_min_ver;  // if missing, defaults to 0, ie. v0.0
     unsigned int bpfloader_max_ver;  // if missing, defaults to 0x10000, ie. v1.0
 
-    // The following fields were added in version 0.2
+    // The following fields were added in version 0.2 (S)
     // kernelVersion() must be >= min_kver and < max_kver
     unsigned int min_kver;
     unsigned int max_kver;
+
+#ifdef V18
+    // The following fields were added in version 0.18 (T)
+    //
+    // These are fixed length strings, padded with null bytes
+    //
+    // Warning: supported values depend on .o location
+    // (additionally a newer Android OS and/or bpfloader may support more values)
+    //
+    // overrides default selinux context (which is based on pin subdir)
+    char selinux_context[BPF_SELINUX_CONTEXT_CHAR_ARRAY_SIZE];
+    //
+    // overrides default prefix (which is based on .o location)
+    char pin_subdir[BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE];
+
+    bool shared;  // use empty string as 'file' component of pin path - allows cross .o map sharing
+    char pad0[3];  // manually pad up to 4 byte alignment, may be used for extensions in the future
+#endif
 };
 
+#ifdef V18
+_Static_assert(sizeof(((struct bpf_map_def *)0)->selinux_context) == 32, "must be 32 bytes");
+_Static_assert(sizeof(((struct bpf_map_def *)0)->pin_subdir) == 32, "must be 32 bytes");
+#endif
+
 // This needs to be updated whenever the above structure definition is expanded.
+#ifdef V18
+_Static_assert(sizeof(struct bpf_map_def) == 116, "sizeof struct bpf_map_def != 116");
+#else
 _Static_assert(sizeof(struct bpf_map_def) == 48, "sizeof struct bpf_map_def != 48");
+#endif
 _Static_assert(__alignof__(struct bpf_map_def) == 4, "__alignof__ struct bpf_map_def != 4");
 _Static_assert(_Alignof(struct bpf_map_def) == 4, "_Alignof struct bpf_map_def != 4");
 
@@ -168,10 +204,23 @@
     unsigned int bpfloader_min_ver;  // if missing, defaults to 0, ie. v0.0
     unsigned int bpfloader_max_ver;  // if missing, defaults to 0x10000, ie. v1.0
 
-    // No new fields in version 0.2
+#ifdef V18
+    // The following fields were added in version 0.18, see description up above in bpf_map_def
+    char selinux_context[BPF_SELINUX_CONTEXT_CHAR_ARRAY_SIZE];
+    char pin_subdir[BPF_PIN_SUBDIR_CHAR_ARRAY_SIZE];
+#endif
 };
 
+#ifdef V18
+_Static_assert(sizeof(((struct bpf_prog_def *)0)->selinux_context) == 32, "must be 32 bytes");
+_Static_assert(sizeof(((struct bpf_prog_def *)0)->pin_subdir) == 32, "must be 32 bytes");
+#endif
+
 // This needs to be updated whenever the above structure definition is expanded.
+#ifdef V18
+_Static_assert(sizeof(struct bpf_prog_def) == 92, "sizeof struct bpf_prog_def != 92");
+#else
 _Static_assert(sizeof(struct bpf_prog_def) == 28, "sizeof struct bpf_prog_def != 28");
+#endif
 _Static_assert(__alignof__(struct bpf_prog_def) == 4, "__alignof__ struct bpf_prog_def != 4");
 _Static_assert(_Alignof(struct bpf_prog_def) == 4, "_Alignof struct bpf_prog_def != 4");