bpfloader: also load from /vendor/etc/bpf/ am: 0f10f3fd9f
Original change: https://android-review.googlesource.com/c/platform/system/bpf/+/1188704
Change-Id: I5e99df4cdc54e29ec5c396319132d809819e3a86
diff --git a/bpfloader/BpfLoader.cpp b/bpfloader/BpfLoader.cpp
index 3f86a56..5c24f0a 100644
--- a/bpfloader/BpfLoader.cpp
+++ b/bpfloader/BpfLoader.cpp
@@ -39,6 +39,7 @@
#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>
@@ -52,10 +53,22 @@
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[] = {
+ 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/",
@@ -71,23 +84,32 @@
.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));
@@ -122,9 +144,9 @@
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/BpfLoadTest.cpp b/libbpf_android/BpfLoadTest.cpp
index d14c7fc..db45da1 100644
--- a/libbpf_android/BpfLoadTest.cpp
+++ b/libbpf_android/BpfLoadTest.cpp
@@ -49,6 +49,14 @@
auto progPath = android::base::GetExecutableDirectory() + "/" + GetParam() + ".o";
bool critical = true;
+
+ 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);
diff --git a/libbpf_android/Loader.cpp b/libbpf_android/Loader.cpp
index fd223a2..eab8e96 100644
--- a/libbpf_android/Loader.cpp
+++ b/libbpf_android/Loader.cpp
@@ -312,16 +312,14 @@
return BPF_ATTACH_TYPE_UNSPEC;
}
-/* If ever needed
static string getSectionName(enum bpf_prog_type type)
{
for (auto& snt : sectionNameTypes)
if (snt.type == type)
return string(snt.name);
- return NULL;
+ return "UNKNOWN SECTION NAME " + std::to_string(type);
}
-*/
static int readProgDefs(ifstream& elfFile, vector<struct bpf_prog_def>& pd,
size_t sizeOfBpfProgDef) {
@@ -401,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;
@@ -426,8 +435,14 @@
if (ret) return ret;
enum bpf_prog_type ptype = getSectionType(name);
+
if (ptype == BPF_PROG_TYPE_UNSPEC) continue;
+ if (!IsAllowed(ptype, allowed, numAllowed)) {
+ ALOGE("Program type %s not permitted here", getSectionName(ptype).c_str());
+ return -1;
+ }
+
// This must be done before '/' is replaced with '_'.
cs_temp.expected_attach_type = getExpectedAttachType(name);
@@ -881,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;
@@ -946,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/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);