Use a isolated process to load bpf program
For the security reason of the bpf program loading process, the
program loading and running operation is moved to a seperate process out
of netd traffic controller. This can help we isolate the program loading
process into a seperate sandbox and apply more strict selinux and
seccomp security policy on it. This action can help providing additional
security fence on CVE-2017-5753.
Test: bpf program pinned at sys/fs/bpf after device boot.
Bug: 30950746
Change-Id: Id194017692343d1f55ec7f44254ff4918e95e2d3
diff --git a/server/TrafficController.cpp b/server/TrafficController.cpp
index f9bc909..9535efe 100644
--- a/server/TrafficController.cpp
+++ b/server/TrafficController.cpp
@@ -29,17 +29,19 @@
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <sys/utsname.h>
+#include <sys/wait.h>
#include <unordered_set>
#include <vector>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
+#include <logwrap/logwrap.h>
#include <netdutils/StatusOr.h>
#include <netdutils/Misc.h>
#include <netdutils/Syscalls.h>
-#include "BpfProgSets.h"
#include "TrafficController.h"
#include "bpf/BpfUtils.h"
@@ -47,7 +49,6 @@
#include "qtaguid/qtaguid.h"
using namespace android::bpf;
-using namespace android::net::bpf_prog;
namespace android {
namespace net {
@@ -62,44 +63,6 @@
using netdutils::StatusOr;
using netdutils::status::ok;
-Status TrafficController::loadAndAttachProgram(bpf_attach_type type, const char* path,
- const char* name, base::unique_fd& cg_fd) {
- base::unique_fd fd;
- int ret = access(path, R_OK);
- if (ret == 0) {
- // The program already exist and we can access it.
- return netdutils::status::ok;
- }
-
- if (errno != ENOENT) {
- // The program exist but we cannot access it.
- return statusFromErrno(errno, StringPrintf("Cannot access %s at path: %s", name, path));
- }
-
- // Program does not exist yet. Load, attach and pin it.
- if (type == BPF_CGROUP_INET_EGRESS) {
- fd.reset(loadEgressProg(mCookieTagMap.get(), mUidStatsMap.get(), mTagStatsMap.get(),
- mUidCounterSetMap.get()));
- } else {
- fd.reset(loadIngressProg(mCookieTagMap.get(), mUidStatsMap.get(), mTagStatsMap.get(),
- mUidCounterSetMap.get()));
- }
- if (fd < 0) {
- return statusFromErrno(errno, StringPrintf("load %s failed", name));
- }
-
- ret = attachProgram(type, fd, cg_fd);
- if (ret) {
- return statusFromErrno(errno, StringPrintf("%s attach failed", name));
- }
-
- ret = mapPin(fd, path);
- if (ret) {
- return statusFromErrno(errno, StringPrintf("Pin %s as file failed(%s)", name, path));
- }
- return netdutils::status::ok;
-}
-
constexpr int kSockDiagMsgType = SOCK_DIAG_BY_FAMILY;
constexpr int kSockDiagDoneMsgType = NLMSG_DONE;
@@ -141,10 +104,6 @@
*/
ALOGI("START to load TrafficController");
- base::unique_fd cg_fd(open(CGROUP_ROOT_PATH, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
- if (cg_fd < 0) {
- return statusFromErrno(errno, "Failed to open the cgroup directory");
- }
ASSIGN_OR_RETURN(mCookieTagMap,
setUpBPFMap(sizeof(uint64_t), sizeof(struct UidTag), COOKIE_UID_MAP_SIZE,
@@ -229,9 +188,33 @@
};
expectOk(mSkDestroyListener->subscribe(kSockDiagDoneMsgType, rxDoneHandler));
- RETURN_IF_NOT_OK(loadAndAttachProgram(BPF_CGROUP_INET_INGRESS, BPF_INGRESS_PROG_PATH,
- "Ingress_prog", cg_fd));
- return loadAndAttachProgram(BPF_CGROUP_INET_EGRESS, BPF_EGRESS_PROG_PATH, "egress_prog", cg_fd);
+ int* status = nullptr;
+
+ std::vector<const char*> prog_args{
+ "/system/bin/bpfloader",
+ };
+ ret = access(BPF_INGRESS_PROG_PATH, R_OK);
+ if (ret != 0 && errno == ENOENT) {
+ prog_args.push_back((char*)"-i");
+ }
+ ret = access(BPF_EGRESS_PROG_PATH, R_OK);
+ if (ret != 0 && errno == ENOENT) {
+ prog_args.push_back((char*)"-e");
+ }
+
+ if (prog_args.size() == 1) {
+ // both program are loaded already.
+ return netdutils::status::ok;
+ }
+
+ prog_args.push_back(nullptr);
+ ret = android_fork_execvp(prog_args.size(), (char**)prog_args.data(), status, false, true);
+ if (ret) {
+ ret = errno;
+ ALOGE("failed to execute %s: %s", prog_args[0], strerror(errno));
+ return statusFromErrno(ret, "run bpf loader failed");
+ }
+ return netdutils::status::ok;
}
int TrafficController::tagSocket(int sockFd, uint32_t tag, uid_t uid) {