summaryrefslogtreecommitdiff
path: root/bpfloader/BpfLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'bpfloader/BpfLoader.cpp')
-rw-r--r--bpfloader/BpfLoader.cpp163
1 files changed, 98 insertions, 65 deletions
diff --git a/bpfloader/BpfLoader.cpp b/bpfloader/BpfLoader.cpp
index 26fb99dd..4b7f74ae 100644
--- a/bpfloader/BpfLoader.cpp
+++ b/bpfloader/BpfLoader.cpp
@@ -50,11 +50,7 @@ using android::base::unique_fd;
using android::netdutils::Slice;
#define BPF_PROG_PATH "/system/etc/bpf"
-
-#define INGRESS_PROG BPF_PROG_PATH"/cgroup_bpf_ingress_prog.o"
-#define EGRESS_PROG BPF_PROG_PATH"/cgroup_bpf_egress_prog.o"
-#define XT_BPF_INGRESS_PROG BPF_PROG_PATH "/xt_bpf_ingress_prog.o"
-#define XT_BPF_EGRESS_PROG BPF_PROG_PATH "/xt_bpf_egress_prog.o"
+#define BPF_PROG_SRC BPF_PROG_PATH "/bpf_kern.o"
#define MAP_LD_CMD_HEAD 0x18
#define FAIL(...) \
@@ -112,7 +108,24 @@ struct ReplacePattern {
}
};
-int loadProg(const char* path, const std::vector<ReplacePattern> &mapPatterns) {
+Slice cgroupIngressProg;
+Slice cgroupEgressProg;
+Slice xtIngressProg;
+Slice xtEgressProg;
+
+Slice getProgFromMem(Slice buffer, Elf64_Shdr* section) {
+ uint64_t progSize = (uint64_t)section->sh_size;
+ Slice progSection = take(drop(buffer, section->sh_offset), progSize);
+ if (progSection.size() < progSize) FAIL("programSection out of bound\n");
+ char* progArray = new char[progSize];
+ Slice progCopy(progArray, progSize);
+ if (copy(progCopy, progSection) != progSize) {
+ FAIL("program cannot be extracted");
+ }
+ return progCopy;
+}
+
+void parseProgramsFromFile(const char* path) {
int fd = open(path, O_RDONLY);
if (fd == -1) {
FAIL("Failed to open %s program: %s", path, strerror(errno));
@@ -127,86 +140,99 @@ int loadProg(const char* path, const std::vector<ReplacePattern> &mapPatterns) {
if ((uint32_t)fileLen < sizeof(Elf64_Ehdr)) FAIL("file size too small for Elf64_Ehdr");
- Elf64_Ehdr* elf = (Elf64_Ehdr*)baseAddr;
+ Slice buffer(baseAddr, fileLen);
+
+ Slice elfHeader = take(buffer, sizeof(Elf64_Ehdr));
+
+ if (elfHeader.size() < sizeof(Elf64_Ehdr)) FAIL("bpf buffer does not have complete elf header");
+ Elf64_Ehdr* elf = (Elf64_Ehdr*)elfHeader.base();
// Find section names string table. This is the section whose index is e_shstrndx.
- if (elf->e_shstrndx == SHN_UNDEF ||
- elf->e_shoff + (elf->e_shstrndx + 1) * sizeof(Elf64_Shdr) > (uint32_t)fileLen) {
+ if (elf->e_shstrndx == SHN_UNDEF) {
FAIL("cannot locate namesSection\n");
}
+ size_t totalSectionSize = (elf->e_shnum) * sizeof(Elf64_Shdr);
+ Slice sections = take(drop(buffer, elf->e_shoff), totalSectionSize);
+ if (sections.size() < totalSectionSize) {
+ FAIL("sections corrupted");
+ }
- Elf64_Shdr* sections = (Elf64_Shdr*)(baseAddr + elf->e_shoff);
-
- Elf64_Shdr* namesSection = sections + elf->e_shstrndx;
+ Slice namesSection = take(drop(sections, elf->e_shstrndx * sizeof(Elf64_Shdr)),
+ sizeof(Elf64_Shdr));
+ if (namesSection.size() != sizeof(Elf64_Shdr)) {
+ FAIL("namesSection corrupted");
+ }
+ size_t strTabOffset = ((Elf64_Shdr*) namesSection.base())->sh_offset;
+ size_t strTabSize = ((Elf64_Shdr*) namesSection.base())->sh_size;
- if (namesSection->sh_offset + namesSection->sh_size > (uint32_t)fileLen)
- FAIL("namesSection out of bound\n");
+ Slice strTab = take(drop(buffer, strTabOffset), strTabSize);
+ if (strTab.size() < strTabSize) {
+ FAIL("string table out of bound\n");
+ }
- const char* strTab = baseAddr + namesSection->sh_offset;
- void* progSection = nullptr;
- uint64_t progSize = 0;
for (int i = 0; i < elf->e_shnum; i++) {
- Elf64_Shdr* section = sections + i;
- if (((char*)section - baseAddr) + sizeof(Elf64_Shdr) > (uint32_t)fileLen) {
- FAIL("next section is out of bound\n");
+ Slice section = take(drop(sections, i * sizeof(Elf64_Shdr)), sizeof(Elf64_Shdr));
+ if (section.size() < sizeof(Elf64_Shdr)) {
+ FAIL("section %d is out of bound, section size: %zu, header size: %zu, total size: %zu",
+ i, section.size(), sizeof(Elf64_Shdr), sections.size());
}
-
- if (!strcmp(strTab + section->sh_name, BPF_PROG_SEC_NAME)) {
- progSection = baseAddr + section->sh_offset;
- progSize = (uint64_t)section->sh_size;
- break;
+ Elf64_Shdr* sectionPtr = (Elf64_Shdr*)section.base();
+ Slice nameSlice = drop(strTab, sectionPtr->sh_name);
+ if (nameSlice.size() == 0) {
+ FAIL("nameSlice out of bound, i: %d, strTabSize: %zu, sh_name: %u", i, strTabSize,
+ sectionPtr->sh_name);
+ }
+ if (!strcmp((char *)nameSlice.base(), BPF_CGROUP_INGRESS_PROG_NAME)) {
+ cgroupIngressProg = getProgFromMem(buffer, sectionPtr);
+ } else if (!strcmp((char *)nameSlice.base(), BPF_CGROUP_EGRESS_PROG_NAME)) {
+ cgroupEgressProg = getProgFromMem(buffer, sectionPtr);
+ } else if (!strcmp((char *)nameSlice.base(), XT_BPF_INGRESS_PROG_NAME)) {
+ xtIngressProg = getProgFromMem(buffer, sectionPtr);
+ } else if (!strcmp((char *)nameSlice.base(), XT_BPF_EGRESS_PROG_NAME)) {
+ xtEgressProg = getProgFromMem(buffer, sectionPtr);
}
}
+}
- if (!progSection) FAIL("program section not found");
- if ((char*)progSection - baseAddr + progSize > (uint32_t)fileLen)
- FAIL("programSection out of bound\n");
-
- char* prog = new char[progSize]();
- memcpy(prog, progSection, progSize);
-
-
- char* mapHead = prog;
- while ((uint64_t)(mapHead - prog + MAP_CMD_SIZE) < progSize) {
+int loadProg(Slice prog, bpf_prog_type type, const std::vector<ReplacePattern>& mapPatterns) {
+ if (prog.size() == 0) {
+ FAIL("Couldn't find or parse program type %d", type);
+ }
+ Slice remaining = prog;
+ while (remaining.size() >= MAP_CMD_SIZE) {
// Scan the program, examining all possible places that might be the start of a map load
- // operation (i.e., all byes of value MAP_LD_CMD_HEAD).
- //
+ // operation (i.e., all bytes of value MAP_LD_CMD_HEAD).
// In each of these places, check whether it is the start of one of the patterns we want to
// replace, and if so, replace it.
- mapHead = (char*)memchr(mapHead, MAP_LD_CMD_HEAD, progSize);
- if (!mapHead) break;
+ Slice mapHead = findFirstMatching(remaining, MAP_LD_CMD_HEAD);
+ if (mapHead.size() < MAP_CMD_SIZE) break;
+ bool replaced = false;
for (const auto& pattern : mapPatterns) {
- if (!memcmp(mapHead, pattern.search.data(), MAP_CMD_SIZE)) {
- memcpy(mapHead, pattern.replace.data(), MAP_CMD_SIZE);
+ if (!memcmp(mapHead.base(), pattern.search.data(), MAP_CMD_SIZE)) {
+ memcpy(mapHead.base(), pattern.replace.data(), MAP_CMD_SIZE);
+ replaced = true;
+ break;
}
}
- mapHead++;
+ remaining = drop(mapHead, replaced ? MAP_CMD_SIZE : sizeof(uint8_t));
}
- Slice insns = Slice(prog, progSize);
char bpf_log_buf[LOG_BUF_SIZE];
Slice bpfLog = Slice(bpf_log_buf, sizeof(bpf_log_buf));
- if (strcmp(path, XT_BPF_INGRESS_PROG) && strcmp(path, XT_BPF_EGRESS_PROG)) {
- return bpfProgLoad(BPF_PROG_TYPE_CGROUP_SKB, insns, "Apache 2.0", 0, bpfLog);
- }
- return bpfProgLoad(BPF_PROG_TYPE_SOCKET_FILTER, insns, "Apache 2.0", 0, bpfLog);
+ return bpfProgLoad(type, prog, "Apache 2.0", 0, bpfLog);
}
int loadAndAttachProgram(bpf_attach_type type, const char* path, const char* name,
std::vector<ReplacePattern> mapPatterns) {
- unique_fd cg_fd(open(CGROUP_ROOT_PATH, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
- if (cg_fd < 0) {
- FAIL("Failed to open the cgroup directory");
- }
unique_fd fd;
if (type == BPF_CGROUP_INET_INGRESS) {
- fd.reset(loadProg(INGRESS_PROG, mapPatterns));
+ fd.reset(loadProg(cgroupIngressProg, BPF_PROG_TYPE_CGROUP_SKB, mapPatterns));
} else if (type == BPF_CGROUP_INET_EGRESS) {
- fd.reset(loadProg(EGRESS_PROG, mapPatterns));
- } else if (!strcmp(name, "xt_bpf_ingress_prog")) {
- fd.reset(loadProg(XT_BPF_INGRESS_PROG, mapPatterns));
- } else if (!strcmp(name, "xt_bpf_egress_prog")) {
- fd.reset(loadProg(XT_BPF_EGRESS_PROG, mapPatterns));
+ fd.reset(loadProg(cgroupEgressProg, BPF_PROG_TYPE_CGROUP_SKB, mapPatterns));
+ } else if (!strcmp(name, XT_BPF_INGRESS_PROG_NAME)) {
+ fd.reset(loadProg(xtIngressProg, BPF_PROG_TYPE_SOCKET_FILTER, mapPatterns));
+ } else if (!strcmp(name, XT_BPF_EGRESS_PROG_NAME)) {
+ fd.reset(loadProg(xtEgressProg, BPF_PROG_TYPE_SOCKET_FILTER, mapPatterns));
} else {
FAIL("Unrecognized program type: %s", name);
}
@@ -216,6 +242,10 @@ int loadAndAttachProgram(bpf_attach_type type, const char* path, const char* nam
}
int ret = 0;
if (type == BPF_CGROUP_INET_EGRESS || type == BPF_CGROUP_INET_INGRESS) {
+ unique_fd cg_fd(open(CGROUP_ROOT_PATH, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
+ if (cg_fd < 0) {
+ FAIL("Failed to open the cgroup directory");
+ }
ret = attachProgram(type, fd, cg_fd);
if (ret) {
FAIL("%s attach failed: %s", name, strerror(errno));
@@ -245,6 +275,7 @@ using android::bpf::UID_STATS_MAP_PATH;
using android::bpf::XT_BPF_EGRESS_PROG_PATH;
using android::bpf::XT_BPF_INGRESS_PROG_PATH;
using android::bpf::ReplacePattern;
+using android::bpf::loadAndAttachProgram;
static void usage(void) {
ALOGE( "Usage: ./bpfloader [-i] [-e]\n"
@@ -297,30 +328,32 @@ int main(int argc, char** argv) {
FAIL("unknown argument %c", opt);
}
}
+ android::bpf::parseProgramsFromFile(BPF_PROG_SRC);
+
if (doIngress) {
- ret = android::bpf::loadAndAttachProgram(BPF_CGROUP_INET_INGRESS, BPF_INGRESS_PROG_PATH,
- "ingress_prog", mapPatterns);
+ ret = loadAndAttachProgram(BPF_CGROUP_INET_INGRESS, BPF_INGRESS_PROG_PATH,
+ BPF_CGROUP_INGRESS_PROG_NAME, mapPatterns);
if (ret) {
FAIL("Failed to set up ingress program");
}
}
if (doEgress) {
- ret = android::bpf::loadAndAttachProgram(BPF_CGROUP_INET_EGRESS, BPF_EGRESS_PROG_PATH,
- "egress_prog", mapPatterns);
+ ret = loadAndAttachProgram(BPF_CGROUP_INET_EGRESS, BPF_EGRESS_PROG_PATH,
+ BPF_CGROUP_EGRESS_PROG_NAME, mapPatterns);
if (ret) {
FAIL("Failed to set up ingress program");
}
}
if (doPrerouting) {
- ret = android::bpf::loadAndAttachProgram(
- MAX_BPF_ATTACH_TYPE, XT_BPF_INGRESS_PROG_PATH, "xt_bpf_ingress_prog", mapPatterns);
+ ret = loadAndAttachProgram(MAX_BPF_ATTACH_TYPE, XT_BPF_INGRESS_PROG_PATH,
+ XT_BPF_INGRESS_PROG_NAME, mapPatterns);
if (ret) {
FAIL("Failed to set up xt_bpf program");
}
}
if (doMangle) {
- ret = android::bpf::loadAndAttachProgram(
- MAX_BPF_ATTACH_TYPE, XT_BPF_EGRESS_PROG_PATH, "xt_bpf_egress_prog", mapPatterns);
+ ret = loadAndAttachProgram(MAX_BPF_ATTACH_TYPE, XT_BPF_EGRESS_PROG_PATH,
+ XT_BPF_EGRESS_PROG_NAME, mapPatterns);
if (ret) {
FAIL("Failed to set up xt_bpf program");
}