Empty merge of sc-v2-dev-plus-aosp-without-vendor@8084891

Bug: 214455710
Merged-In: Id9ac888d5519b2a8663232610d36386cabfe4e94
Change-Id: I16dd4452290d8b28bbf525c3d4906ba1b2bfeb9e
diff --git a/bpfloader/Android.bp b/bpfloader/Android.bp
index beff687..4dbabfa 100644
--- a/bpfloader/Android.bp
+++ b/bpfloader/Android.bp
@@ -55,6 +55,7 @@
     init_rc: ["bpfloader.rc"],
 
     required: [
+        "btfloader",
         "time_in_state.o"
     ],
 
diff --git a/bpfloader/BpfLoader.cpp b/bpfloader/BpfLoader.cpp
index 7a68894..5c24f0a 100644
--- a/bpfloader/BpfLoader.cpp
+++ b/bpfloader/BpfLoader.cpp
@@ -38,6 +38,8 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <android-base/logging.h>
+#include <android-base/macros.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
@@ -51,37 +53,63 @@
 using android::base::EndsWith;
 using std::string;
 
-struct {
+// see b/162057235. For arbitrary program types, the concern is that due to the lack of
+// SELinux access controls over BPF program attachpoints, we have no way to control the
+// attachment of programs to shared resources (or to detect when a shared resource
+// has one BPF program replace another that is attached there)
+constexpr bpf_prog_type kVendorAllowedProgTypes[] = {
+        BPF_PROG_TYPE_TRACEPOINT,
+};
+
+struct Location {
     const char* const dir;
     const char* const prefix;
-} locations[] = {
-        // Tethering mainline module
+    const bpf_prog_type* allowedProgTypes = nullptr;
+    size_t allowedProgTypesLength = 0;
+};
+
+const Location locations[] = {
+        // Tethering mainline module: tether offload
         {
                 .dir = "/apex/com.android.tethering/etc/bpf/",
                 .prefix = "tethering/",
         },
+        // Tethering mainline module: netd, clatd, ...etc
+        {
+                .dir = "/apex/com.android.tethering/etc/bpf/net_shared/",
+                .prefix = "",
+        },
         // Core operating system
         {
                 .dir = "/system/etc/bpf/",
                 .prefix = "",
         },
+        // Vendor operating system
+        {
+                .dir = "/vendor/etc/bpf/",
+                .prefix = "vendor/",
+                .allowedProgTypes = kVendorAllowedProgTypes,
+                .allowedProgTypesLength = arraysize(kVendorAllowedProgTypes),
+        },
 };
 
-int loadAllElfObjects(const char* const progDir, const char* const prefix) {
+int loadAllElfObjects(const Location& location) {
     int retVal = 0;
     DIR* dir;
     struct dirent* ent;
 
-    if ((dir = opendir(progDir)) != NULL) {
+    if ((dir = opendir(location.dir)) != NULL) {
         while ((ent = readdir(dir)) != NULL) {
             string s = ent->d_name;
             if (!EndsWith(s, ".o")) continue;
 
-            string progPath(progDir);
+            string progPath(location.dir);
             progPath += s;
 
             bool critical;
-            int ret = android::bpf::loadProg(progPath.c_str(), &critical, prefix);
+            int ret = android::bpf::loadProg(progPath.c_str(), &critical, location.prefix,
+                                             location.allowedProgTypes,
+                                             location.allowedProgTypesLength);
             if (ret) {
                 if (critical) retVal = ret;
                 ALOGE("Failed to load object: %s, ret: %s", progPath.c_str(), std::strerror(-ret));
@@ -111,11 +139,14 @@
     }
 }
 
-int main() {
+int main(int argc, char** argv) {
+    (void)argc;
+    android::base::InitLogging(argv, &android::base::KernelLogger);
+
     // Load all ELF objects, create programs and maps, and pin them
-    for (const auto location : locations) {
+    for (const auto& location : locations) {
         createSysFsBpfSubDir(location.prefix);
-        if (loadAllElfObjects(location.dir, location.prefix) != 0) {
+        if (loadAllElfObjects(location) != 0) {
             ALOGE("=== CRITICAL FAILURE LOADING BPF PROGRAMS FROM %s ===", location.dir);
             ALOGE("If this triggers reliably, you're probably missing kernel options or patches.");
             ALOGE("If this triggers randomly, you might be hitting some memory allocation "
diff --git a/libbpf_android/Android.bp b/libbpf_android/Android.bp
index 3b58c00..1fac19d 100644
--- a/libbpf_android/Android.bp
+++ b/libbpf_android/Android.bp
@@ -22,22 +22,6 @@
     default_applicable_licenses: ["system_bpf_license"],
 }
 
-cc_library_headers {
-    name: "libbpf_android_headers",
-    vendor_available: false,
-    host_supported: false,
-    native_bridge_supported: true,
-    export_include_dirs: ["include"],
-    target: {
-        linux_bionic: {
-            enabled: true,
-        },
-    },
-    sdk_version: "30",
-    header_libs: ["bpf_syscall_wrappers"],
-    export_header_lib_headers: ["bpf_syscall_wrappers"],
-}
-
 cc_library {
     name: "libbpf_android",
     vendor_available: false,
@@ -59,17 +43,16 @@
         "libutils",
         "liblog",
         "libbpf_bcc",
+        "libbpf_minimal",
     ],
     header_libs: [
         "bpf_headers",
-        "libbpf_android_headers",
     ],
     export_header_lib_headers: [
-        "libbpf_android_headers",
         "bpf_headers",
     ],
     export_shared_lib_headers: ["libbpf_bcc"],
-    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
 
     defaults: ["bpf_defaults"],
     cflags: [
@@ -81,6 +64,7 @@
 
 cc_test {
     name: "libbpf_load_test",
+    test_suites: ["general-tests"],
     header_libs: ["bpf_headers"],
     srcs: [
         "BpfLoadTest.cpp",
@@ -95,13 +79,15 @@
     shared_libs: [
         "libbpf_android",
         "libbpf_bcc",
+        "libbpf_minimal",
         "libbase",
         "liblog",
         "libutils",
     ],
 
-    required: [
-        "bpf_load_tp_prog.o",
+    data: [
+        ":bpf_load_tp_prog.o",
+        ":bpf_load_tp_prog_btf.o",
     ],
     require_root: true,
 }
diff --git a/libbpf_android/BpfLoadTest.cpp b/libbpf_android/BpfLoadTest.cpp
index a058263..db45da1 100644
--- a/libbpf_android/BpfLoadTest.cpp
+++ b/libbpf_android/BpfLoadTest.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <android-base/file.h>
 #include <android-base/macros.h>
 #include <gtest/gtest.h>
 #include <stdlib.h>
@@ -23,29 +24,43 @@
 #include "bpf/BpfUtils.h"
 #include "include/libbpf_android.h"
 
-using ::testing::Test;
-
-constexpr const char tp_prog_path[] =
-        "/sys/fs/bpf/prog_bpf_load_tp_prog_tracepoint_sched_sched_switch";
-constexpr const char tp_map_path[] = "/sys/fs/bpf/map_bpf_load_tp_prog_cpu_pid_map";
+using ::testing::TestWithParam;
 
 namespace android {
 namespace bpf {
 
-class BpfLoadTest : public testing::Test {
+class BpfLoadTest : public TestWithParam<std::string> {
   protected:
     BpfLoadTest() {}
     int mProgFd;
+    std::string mTpProgPath;
+    std::string mTpNeverLoadProgPath;
+    std::string mTpMapPath;;
 
     void SetUp() {
-        unlink(tp_prog_path);
-        unlink(tp_map_path);
+        mTpProgPath = "/sys/fs/bpf/prog_" + GetParam() + "_tracepoint_sched_sched_switch";
+        unlink(mTpProgPath.c_str());
 
+        mTpNeverLoadProgPath = "/sys/fs/bpf/prog_" + GetParam() + "_tracepoint_sched_sched_wakeup";
+        unlink(mTpNeverLoadProgPath.c_str());
+
+        mTpMapPath = "/sys/fs/bpf/map_" + GetParam() + "_cpu_pid_map";
+        unlink(mTpMapPath.c_str());
+
+        auto progPath = android::base::GetExecutableDirectory() + "/" + GetParam() + ".o";
         bool critical = true;
-        EXPECT_EQ(android::bpf::loadProg("/system/etc/bpf/bpf_load_tp_prog.o", &critical), 0);
+
+        bpf_prog_type kAllowed[] = {
+                BPF_PROG_TYPE_UNSPEC,
+        };
+        EXPECT_EQ(android::bpf::loadProg(progPath.c_str(), &critical, "", kAllowed,
+                                         arraysize(kAllowed)),
+                  -1);
+
+        EXPECT_EQ(android::bpf::loadProg(progPath.c_str(), &critical), 0);
         EXPECT_EQ(false, critical);
 
-        mProgFd = bpf_obj_get(tp_prog_path);
+        mProgFd = bpf_obj_get(mTpProgPath.c_str());
         EXPECT_GT(mProgFd, 0);
 
         int ret = bpf_attach_tracepoint(mProgFd, "sched", "sched_switch");
@@ -54,14 +69,14 @@
 
     void TearDown() {
         close(mProgFd);
-        unlink(tp_prog_path);
-        unlink(tp_map_path);
+        unlink(mTpProgPath.c_str());
+        unlink(mTpMapPath.c_str());
     }
 
     void checkMapNonZero() {
         // The test program installs a tracepoint on sched:sched_switch
         // and expects the kernel to populate a PID corresponding to CPU
-        android::bpf::BpfMap<uint32_t, uint32_t> m(tp_map_path);
+        android::bpf::BpfMap<uint32_t, uint32_t> m(mTpMapPath.c_str());
 
         // Wait for program to run a little
         sleep(1);
@@ -81,11 +96,39 @@
         EXPECT_RESULT_OK(m.iterateWithValue(iterFunc));
         EXPECT_EQ(non_zero, 1);
     }
+
+    void checkMapBtf() {
+        // Earlier kernels lack BPF_BTF_LOAD support
+        if (!isAtLeastKernelVersion(4, 19, 0)) GTEST_SKIP() << "pre-4.19 kernel does not support BTF";
+
+        const bool haveBtf = GetParam().find("btf") != std::string::npos;
+
+        std::string str;
+        EXPECT_EQ(android::base::ReadFileToString(mTpMapPath, &str), haveBtf);
+        if (haveBtf) EXPECT_FALSE(str.empty());
+    }
+
+    void checkKernelVersionEnforced() {
+        EXPECT_EQ(bpf_obj_get(mTpNeverLoadProgPath.c_str()), -1);
+        EXPECT_EQ(errno, ENOENT);
+    }
 };
 
-TEST_F(BpfLoadTest, bpfCheckMap) {
+INSTANTIATE_TEST_SUITE_P(BpfLoadTests, BpfLoadTest,
+                         ::testing::Values("bpf_load_tp_prog",
+                                           "bpf_load_tp_prog_btf"));
+
+TEST_P(BpfLoadTest, bpfCheckMap) {
     checkMapNonZero();
 }
 
+TEST_P(BpfLoadTest, bpfCheckBtf) {
+    checkMapBtf();
+}
+
+TEST_P(BpfLoadTest, bpfCheckMinKernelVersionEnforced) {
+    checkKernelVersionEnforced();
+}
+
 }  // namespace bpf
 }  // namespace android
diff --git a/libbpf_android/Loader.cpp b/libbpf_android/Loader.cpp
index abe1704..eab8e96 100644
--- a/libbpf_android/Loader.cpp
+++ b/libbpf_android/Loader.cpp
@@ -24,26 +24,33 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sysexits.h>
 #include <sys/stat.h>
 #include <sys/utsname.h>
+#include <sys/wait.h>
 #include <unistd.h>
 
-// This is BpfLoader v0.8
+// This is BpfLoader v0.10
 #define BPFLOADER_VERSION_MAJOR 0u
-#define BPFLOADER_VERSION_MINOR 8u
+#define BPFLOADER_VERSION_MINOR 10u
 #define BPFLOADER_VERSION ((BPFLOADER_VERSION_MAJOR << 16) | BPFLOADER_VERSION_MINOR)
 
 #include "bpf/BpfUtils.h"
 #include "bpf/bpf_map_def.h"
 #include "include/libbpf_android.h"
 
+#include <bpf/bpf.h>
+
 #include <cstdlib>
 #include <fstream>
 #include <iostream>
 #include <optional>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
+#include <android-base/cmsg.h>
+#include <android-base/file.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 
@@ -52,6 +59,9 @@
 // Size of the BPF log buffer for verifier logging
 #define BPF_LOAD_LOG_SZ 0xfffff
 
+// Unspecified attach type is 0 which is BPF_CGROUP_INET_INGRESS.
+#define BPF_ATTACH_TYPE_UNSPEC BPF_CGROUP_INET_INGRESS
+
 using android::base::StartsWith;
 using android::base::unique_fd;
 using std::ifstream;
@@ -77,6 +87,7 @@
 typedef struct {
     const char* name;
     enum bpf_prog_type type;
+    enum bpf_attach_type expected_attach_type;
 } sectionType;
 
 /*
@@ -90,19 +101,21 @@
  * Instead use the DEFINE_(BPF|XDP)_(PROG|MAP)... & LICENSE/CRITICAL macros.
  */
 sectionType sectionNameTypes[] = {
-        {"cgroupskb/", BPF_PROG_TYPE_CGROUP_SKB},
-        {"cgroupsock/", BPF_PROG_TYPE_CGROUP_SOCK},
-        {"cgroupsockaddr/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR},
-        {"kprobe/", BPF_PROG_TYPE_KPROBE},
-        {"schedact/", BPF_PROG_TYPE_SCHED_ACT},
-        {"schedcls/", BPF_PROG_TYPE_SCHED_CLS},
-        {"skfilter/", BPF_PROG_TYPE_SOCKET_FILTER},
-        {"tracepoint/", BPF_PROG_TYPE_TRACEPOINT},
-        {"xdp/", BPF_PROG_TYPE_XDP},
+        {"bind4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_BIND},
+        {"bind6/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_BIND},
+        {"cgroupskb/", BPF_PROG_TYPE_CGROUP_SKB, BPF_ATTACH_TYPE_UNSPEC},
+        {"cgroupsock/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_ATTACH_TYPE_UNSPEC},
+        {"kprobe/", BPF_PROG_TYPE_KPROBE, BPF_ATTACH_TYPE_UNSPEC},
+        {"schedact/", BPF_PROG_TYPE_SCHED_ACT, BPF_ATTACH_TYPE_UNSPEC},
+        {"schedcls/", BPF_PROG_TYPE_SCHED_CLS, BPF_ATTACH_TYPE_UNSPEC},
+        {"skfilter/", BPF_PROG_TYPE_SOCKET_FILTER, BPF_ATTACH_TYPE_UNSPEC},
+        {"tracepoint/", BPF_PROG_TYPE_TRACEPOINT, BPF_ATTACH_TYPE_UNSPEC},
+        {"xdp/", BPF_PROG_TYPE_XDP, BPF_ATTACH_TYPE_UNSPEC},
 };
 
 typedef struct {
     enum bpf_prog_type type;
+    enum bpf_attach_type expected_attach_type;
     string name;
     vector<char> data;
     vector<char> rel_data;
@@ -293,27 +306,19 @@
     return BPF_PROG_TYPE_UNSPEC;
 }
 
-/* If ever needed
+static enum bpf_attach_type getExpectedAttachType(string& name) {
+    for (auto& snt : sectionNameTypes)
+        if (StartsWith(name, snt.name)) return snt.expected_attach_type;
+    return BPF_ATTACH_TYPE_UNSPEC;
+}
+
 static string getSectionName(enum bpf_prog_type type)
 {
     for (auto& snt : sectionNameTypes)
         if (snt.type == type)
             return string(snt.name);
 
-    return NULL;
-}
-*/
-
-static bool isRelSection(codeSection& cs, string& name) {
-    for (auto& snt : sectionNameTypes) {
-        if (snt.type != cs.type) continue;
-
-        if (StartsWith(name, string(".rel") + snt.name))
-            return true;
-        else
-            return false;
-    }
-    return false;
+    return "UNKNOWN SECTION NAME " + std::to_string(type);
 }
 
 static int readProgDefs(ifstream& elfFile, vector<struct bpf_prog_def>& pd,
@@ -349,7 +354,8 @@
     return 0;
 }
 
-static int getSectionSymNames(ifstream& elfFile, const string& sectionName, vector<string>& names) {
+static int getSectionSymNames(ifstream& elfFile, const string& sectionName, vector<string>& names,
+                              optional<unsigned> symbolType = std::nullopt) {
     int ret;
     string name;
     vector<Elf64_Sym> symtab;
@@ -380,6 +386,8 @@
     }
 
     for (int i = 0; i < (int)symtab.size(); i++) {
+        if (symbolType.has_value() && ELF_ST_TYPE(symtab[i].st_info) != symbolType) continue;
+
         if (symtab[i].st_shndx == sec_idx) {
             string s;
             ret = getSymName(elfFile, symtab[i].st_name, s);
@@ -391,8 +399,19 @@
     return 0;
 }
 
+static bool IsAllowed(bpf_prog_type type, const bpf_prog_type* allowed, size_t numAllowed) {
+    if (allowed == nullptr) return true;
+
+    for (size_t i = 0; i < numAllowed; i++) {
+        if (type == allowed[i]) return true;
+    }
+
+    return false;
+}
+
 /* Read a section by its index - for ex to get sec hdr strtab blob */
-static int readCodeSections(ifstream& elfFile, vector<codeSection>& cs, size_t sizeOfBpfProgDef) {
+static int readCodeSections(ifstream& elfFile, vector<codeSection>& cs, size_t sizeOfBpfProgDef,
+                            const bpf_prog_type* allowed, size_t numAllowed) {
     vector<Elf64_Shdr> shTable;
     int entries, ret = 0;
 
@@ -416,27 +435,36 @@
         if (ret) return ret;
 
         enum bpf_prog_type ptype = getSectionType(name);
-        if (ptype != BPF_PROG_TYPE_UNSPEC) {
-            string oldName = name;
 
-            // convert all slashes to underscores
-            std::replace(name.begin(), name.end(), '/', '_');
+        if (ptype == BPF_PROG_TYPE_UNSPEC) continue;
 
-            cs_temp.type = ptype;
-            cs_temp.name = name;
+        if (!IsAllowed(ptype, allowed, numAllowed)) {
+            ALOGE("Program type %s not permitted here", getSectionName(ptype).c_str());
+            return -1;
+        }
 
-            ret = readSectionByIdx(elfFile, i, cs_temp.data);
-            if (ret) return ret;
-            ALOGD("Loaded code section %d (%s)\n", i, name.c_str());
+        // This must be done before '/' is replaced with '_'.
+        cs_temp.expected_attach_type = getExpectedAttachType(name);
 
-            vector<string> csSymNames;
-            ret = getSectionSymNames(elfFile, oldName, csSymNames);
-            if (ret || !csSymNames.size()) return ret;
-            for (size_t i = 0; i < progDefNames.size(); ++i) {
-                if (!progDefNames[i].compare(csSymNames[0] + "_def")) {
-                    cs_temp.prog_def = pd[i];
-                    break;
-                }
+        string oldName = name;
+
+        // convert all slashes to underscores
+        std::replace(name.begin(), name.end(), '/', '_');
+
+        cs_temp.type = ptype;
+        cs_temp.name = name;
+
+        ret = readSectionByIdx(elfFile, i, cs_temp.data);
+        if (ret) return ret;
+        ALOGD("Loaded code section %d (%s)\n", i, name.c_str());
+
+        vector<string> csSymNames;
+        ret = getSectionSymNames(elfFile, oldName, csSymNames, STT_FUNC);
+        if (ret || !csSymNames.size()) return ret;
+        for (size_t i = 0; i < progDefNames.size(); ++i) {
+            if (!progDefNames[i].compare(csSymNames[0] + "_def")) {
+                cs_temp.prog_def = pd[i];
+                break;
             }
         }
 
@@ -445,7 +473,7 @@
             ret = getSymName(elfFile, shTable[i + 1].sh_name, name);
             if (ret) return ret;
 
-            if (isRelSection(cs_temp, name)) {
+            if (name == (".rel" + oldName)) {
                 ret = readSectionByIdx(elfFile, i + 1, cs_temp.rel_data);
                 if (ret) return ret;
                 ALOGD("Loaded relo section %d (%s)\n", i, name.c_str());
@@ -472,12 +500,88 @@
     return getSymName(elfFile, symtab[index].st_name, name);
 }
 
+static bool waitpidTimeout(pid_t pid, int timeoutMs) {
+    // Add SIGCHLD to the signal set.
+    sigset_t child_mask, original_mask;
+    sigemptyset(&child_mask);
+    sigaddset(&child_mask, SIGCHLD);
+    if (sigprocmask(SIG_BLOCK, &child_mask, &original_mask) == -1) return false;
+
+    // Wait for a SIGCHLD notification.
+    errno = 0;
+    timespec ts = {0, timeoutMs * 1000000};
+    int wait_result = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, nullptr, &ts));
+
+    // Restore the original signal set.
+    sigprocmask(SIG_SETMASK, &original_mask, nullptr);
+
+    if (wait_result == -1) return false;
+
+    int status;
+    return TEMP_FAILURE_RETRY(waitpid(pid, &status, WNOHANG)) == pid;
+}
+
+static std::optional<unique_fd> getMapBtfInfo(const char* elfPath,
+                         std::unordered_map<string, std::pair<uint32_t, uint32_t>> &btfTypeIds) {
+    unique_fd bpfloaderSocket, btfloaderSocket;
+    if (!android::base::Socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, &bpfloaderSocket,
+                                   &btfloaderSocket)) {
+        return {};
+    }
+
+    unique_fd pipeRead, pipeWrite;
+    if (!android::base::Pipe(&pipeRead, &pipeWrite, O_NONBLOCK)) {
+        return {};
+    }
+
+    pid_t pid = fork();
+    if (pid < 0) return {};
+    if (!pid) {
+        bpfloaderSocket.reset();
+        pipeRead.reset();
+        auto socketFdStr = std::to_string(btfloaderSocket.release());
+        auto pipeFdStr = std::to_string(pipeWrite.release());
+
+        if (execl("/system/bin/btfloader", "/system/bin/btfloader", socketFdStr.c_str(),
+                  pipeFdStr.c_str(), elfPath, NULL) == -1) {
+            ALOGW("exec btfloader failed with errno %d (%s)\n", errno, strerror(errno));
+            exit(EX_UNAVAILABLE);
+        }
+    }
+    btfloaderSocket.reset();
+    pipeWrite.reset();
+    if (!waitpidTimeout(pid, 100)) {
+        kill(pid, SIGKILL);
+        return {};
+    }
+
+    unique_fd btfFd;
+    if (android::base::ReceiveFileDescriptors(bpfloaderSocket, nullptr, 0, &btfFd)) return {};
+
+    std::string btfTypeIdStr;
+    if (!android::base::ReadFdToString(pipeRead, &btfTypeIdStr)) return {};
+    if (btfFd.get() < 0) return {};
+
+    const auto mapTypeIdLines = android::base::Split(btfTypeIdStr, "\n");
+    for (const auto &line : mapTypeIdLines) {
+        const auto vec = android::base::Split(line, " ");
+        // Splitting on newline will give us one empty line
+        if (vec.size() != 3) continue;
+        const int kTid = atoi(vec[1].c_str());
+        const int vTid = atoi(vec[2].c_str());
+        if (!kTid || !vTid) return {};
+        btfTypeIds[vec[0]] = std::make_pair(kTid, vTid);
+    }
+    return btfFd;
+}
+
 static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& mapFds,
                       const char* prefix, size_t sizeOfBpfMapDef) {
     int ret;
-    vector<char> mdData;
+    vector<char> mdData, btfData;
     vector<struct bpf_map_def> md;
     vector<string> mapNames;
+    std::unordered_map<string, std::pair<uint32_t, uint32_t>> btfTypeIdMap;
     string fname = pathToFilename(string(elfPath), true);
 
     ret = readSectionByName("maps", elfFile, mdData);
@@ -510,6 +614,11 @@
     ret = getSectionSymNames(elfFile, "maps", mapNames);
     if (ret) return ret;
 
+    std::optional<unique_fd> btfFd;
+    if (!readSectionByName(".BTF", elfFile, btfData)) {
+        btfFd = getMapBtfInfo(elfPath, btfTypeIdMap);
+    }
+
     unsigned kvers = kernelVersion();
 
     for (int i = 0; i < (int)mapNames.size(); i++) {
@@ -575,8 +684,20 @@
                 // programs as being 5.4+...
                 type = BPF_MAP_TYPE_HASH;
             }
-            fd.reset(bpf_create_map(type, mapNames[i].c_str(), md[i].key_size, md[i].value_size,
-                                    md[i].max_entries, md[i].map_flags));
+            struct bpf_create_map_attr attr = {
+                .name = mapNames[i].c_str(),
+                .map_type = type,
+                .map_flags = md[i].map_flags,
+                .key_size = md[i].key_size,
+                .value_size = md[i].value_size,
+                .max_entries = md[i].max_entries,
+            };
+            if (btfFd.has_value() && btfTypeIdMap.find(mapNames[i]) != btfTypeIdMap.end()) {
+                attr.btf_fd = btfFd->get();
+                attr.btf_key_type_id = btfTypeIdMap.at(mapNames[i]).first;
+                attr.btf_value_type_id = btfTypeIdMap.at(mapNames[i]).second;
+            }
+            fd.reset(bcc_create_map_xattr(&attr, true));
             saved_errno = errno;
             ALOGD("bpf_create_map name %s, ret: %d\n", mapNames[i].c_str(), fd.get());
         }
@@ -724,9 +845,18 @@
         } else {
             vector<char> log_buf(BPF_LOAD_LOG_SZ, 0);
 
-            fd = bpf_prog_load(cs[i].type, name.c_str(), (struct bpf_insn*)cs[i].data.data(),
-                               cs[i].data.size(), license.c_str(), kvers, 0, log_buf.data(),
-                               log_buf.size());
+            struct bpf_load_program_attr attr = {
+                .prog_type = cs[i].type,
+                .name = name.c_str(),
+                .insns = (struct bpf_insn*)cs[i].data.data(),
+                .license = license.c_str(),
+                .log_level = 0,
+                .expected_attach_type = cs[i].expected_attach_type,
+            };
+
+            fd = bcc_prog_load_xattr(&attr, cs[i].data.size(), log_buf.data(), log_buf.size(),
+                    true);
+
             ALOGD("bpf_prog_load lib call for %s (%s) returned fd: %d (%s)\n", elfPath,
                   cs[i].name.c_str(), fd, (fd < 0 ? std::strerror(errno) : "no error"));
 
@@ -766,7 +896,8 @@
     return 0;
 }
 
-int loadProg(const char* elfPath, bool* isCritical, const char* prefix) {
+int loadProg(const char* elfPath, bool* isCritical, const char* prefix,
+             const bpf_prog_type* allowed, size_t numAllowed) {
     vector<char> license;
     vector<char> critical;
     vector<codeSection> cs;
@@ -831,7 +962,7 @@
         return -1;
     }
 
-    ret = readCodeSections(elfFile, cs, sizeOfBpfProgDef);
+    ret = readCodeSections(elfFile, cs, sizeOfBpfProgDef, allowed, numAllowed);
     if (ret) {
         ALOGE("Couldn't read all code sections in %s\n", elfPath);
         return ret;
diff --git a/libbpf_android/TEST_MAPPING b/libbpf_android/TEST_MAPPING
new file mode 100644
index 0000000..90892fe
--- /dev/null
+++ b/libbpf_android/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "libbpf_load_test"
+    }
+  ]
+}
diff --git a/libbpf_android/include/libbpf_android.h b/libbpf_android/include/libbpf_android.h
index a3d5f03..3fb777b 100644
--- a/libbpf_android/include/libbpf_android.h
+++ b/libbpf_android/include/libbpf_android.h
@@ -24,7 +24,8 @@
 namespace bpf {
 
 // BPF loader implementation. Loads an eBPF ELF object
-int loadProg(const char* elfPath, bool* isCritical, const char* prefix = "");
+int loadProg(const char* elfPath, bool* isCritical, const char* prefix = "",
+             const bpf_prog_type* allowed = nullptr, size_t numAllowed = 0);
 
 // Exposed for testing
 unsigned int readSectionUint(const char* name, std::ifstream& elfFile, unsigned int defVal);