New bpfloader netd kernel program
am: c1dd7648b1
Change-Id: I543955a4d19bc6fd4cd79b6bdd6ea547de217b63
diff --git a/bpfloader/Android.bp b/bpfloader/Android.bp
index 9f92ce3..22b6d73 100644
--- a/bpfloader/Android.bp
+++ b/bpfloader/Android.bp
@@ -44,19 +44,9 @@
],
required: [
- "bpf_kern.o",
+ "netd.o",
// Uncomment once security related patches ready
// "time_in_state.o",
],
}
-
-bpf {
- name: "bpf_kern.o",
- srcs: ["bpf_kern.c"],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- include_dirs: ["system/netd/libnetdbpf/include"],
-}
diff --git a/bpfloader/BpfLoader.cpp b/bpfloader/BpfLoader.cpp
index 169ff4c..966f3f6 100644
--- a/bpfloader/BpfLoader.cpp
+++ b/bpfloader/BpfLoader.cpp
@@ -53,7 +53,6 @@
using std::string;
#define BPF_PROG_PATH "/system/etc/bpf/"
-#define BPF_PROG_SRC BPF_PROG_PATH "bpf_kern.o"
#define CLEANANDEXIT(ret, mapPatterns) \
do { \
@@ -89,37 +88,4 @@
int main() {
// Load all ELF objects, create programs and maps, and pin them
loadAllElfObjects();
-
- const std::vector<BpfMapInfo> mapPatterns = {
- BpfMapInfo(COOKIE_TAG_MAP, COOKIE_TAG_MAP_PATH),
- BpfMapInfo(UID_COUNTERSET_MAP, UID_COUNTERSET_MAP_PATH),
- BpfMapInfo(APP_UID_STATS_MAP, APP_UID_STATS_MAP_PATH),
- BpfMapInfo(UID_STATS_MAP, UID_STATS_MAP_PATH),
- BpfMapInfo(TAG_STATS_MAP, TAG_STATS_MAP_PATH),
- BpfMapInfo(IFACE_STATS_MAP, IFACE_STATS_MAP_PATH),
- BpfMapInfo(CONFIGURATION_MAP, CONFIGURATION_MAP_PATH),
- BpfMapInfo(UID_OWNER_MAP, UID_OWNER_MAP_PATH),
- };
- for (size_t i = 0; i < mapPatterns.size(); i++) {
- if (mapPatterns[i].fd < 0) {
- ALOGE("Rerieve Map from %s failed: %d", mapPatterns[i].path.c_str(), mapPatterns[i].fd);
- CLEANANDEXIT(-1, mapPatterns);
- }
- }
- BpfProgInfo programs[] = {
- {BPF_CGROUP_INET_EGRESS, BPF_EGRESS_PROG_PATH, BPF_CGROUP_EGRESS_PROG_NAME,
- BPF_PROG_TYPE_CGROUP_SKB, unique_fd(-1)},
- {BPF_CGROUP_INET_INGRESS, BPF_INGRESS_PROG_PATH, BPF_CGROUP_INGRESS_PROG_NAME,
- BPF_PROG_TYPE_CGROUP_SKB, unique_fd(-1)},
- {MAX_BPF_ATTACH_TYPE, XT_BPF_INGRESS_PROG_PATH, XT_BPF_INGRESS_PROG_NAME,
- BPF_PROG_TYPE_SOCKET_FILTER, unique_fd(-1)},
- {MAX_BPF_ATTACH_TYPE, XT_BPF_EGRESS_PROG_PATH, XT_BPF_EGRESS_PROG_NAME,
- BPF_PROG_TYPE_SOCKET_FILTER, unique_fd(-1)},
- {MAX_BPF_ATTACH_TYPE, XT_BPF_WHITELIST_PROG_PATH, XT_BPF_WHITELIST_PROG_NAME,
- BPF_PROG_TYPE_SOCKET_FILTER, unique_fd(-1)},
- {MAX_BPF_ATTACH_TYPE, XT_BPF_BLACKLIST_PROG_PATH, XT_BPF_BLACKLIST_PROG_NAME,
- BPF_PROG_TYPE_SOCKET_FILTER, unique_fd(-1)}};
- int ret = android::bpf::parseProgramsFromFile(BPF_PROG_SRC, programs, ARRAY_SIZE(programs),
- mapPatterns);
- CLEANANDEXIT(ret, mapPatterns);
}
diff --git a/libbpf_android/BpfUtils.cpp b/libbpf_android/BpfUtils.cpp
index 9e2ff44..9f482d6 100644
--- a/libbpf_android/BpfUtils.cpp
+++ b/libbpf_android/BpfUtils.cpp
@@ -167,7 +167,7 @@
return bpf(BPF_OBJ_PIN, Slice(&attr, sizeof(attr)));
}
-int mapRetrieve(const char* pathname, uint32_t flag) {
+int bpfFdGet(const char* pathname, uint32_t flag) {
bpf_attr attr;
memset(&attr, 0, sizeof(attr));
attr.pathname = ptr_to_u64((void*)pathname);
@@ -175,6 +175,10 @@
return bpf(BPF_OBJ_GET, Slice(&attr, sizeof(attr)));
}
+int mapRetrieve(const char* pathname, uint32_t flag) {
+ return bpfFdGet(pathname, flag);
+}
+
int attachProgram(bpf_attach_type type, uint32_t prog_fd, uint32_t cg_fd) {
bpf_attr attr;
memset(&attr, 0, sizeof(attr));
diff --git a/libbpf_android/include/bpf/BpfUtils.h b/libbpf_android/include/bpf/BpfUtils.h
index afebb4a..6bb1f0f 100644
--- a/libbpf_android/include/bpf/BpfUtils.h
+++ b/libbpf_android/include/bpf/BpfUtils.h
@@ -143,6 +143,7 @@
int bpfProgLoad(bpf_prog_type prog_type, netdutils::Slice bpf_insns, const char* license,
uint32_t kern_version, netdutils::Slice bpf_log);
int bpfFdPin(const base::unique_fd& map_fd, const char* pathname);
+int bpfFdGet(const char* pathname, uint32_t flags);
int attachProgram(bpf_attach_type type, uint32_t prog_fd, uint32_t cg_fd);
int detachProgram(bpf_attach_type type, uint32_t cg_fd);
uint64_t getSocketCookie(int sockFd);
diff --git a/progs/Android.bp b/progs/Android.bp
new file mode 100644
index 0000000..35ba797
--- /dev/null
+++ b/progs/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// bpf kernel programs
+//
+bpf {
+ name: "netd.o",
+ srcs: ["netd.c"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ include_dirs: ["system/netd/libnetdbpf/include"],
+}
diff --git a/bpfloader/bpf_kern.c b/progs/netd.c
similarity index 73%
rename from bpfloader/bpf_kern.c
rename to progs/netd.c
index 4fe8140..0ea51a9 100644
--- a/bpfloader/bpf_kern.c
+++ b/progs/netd.c
@@ -14,47 +14,48 @@
* limitations under the License.
*/
+#include "netd.h"
#include <linux/bpf.h>
-#include "bpf_kern.h"
-
-ELF_SEC(BPF_CGROUP_INGRESS_PROG_NAME)
+SEC("cgroupskb/ingress/stats")
int bpf_cgroup_ingress(struct __sk_buff* skb) {
return bpf_traffic_account(skb, BPF_INGRESS);
}
-ELF_SEC(BPF_CGROUP_EGRESS_PROG_NAME)
+SEC("cgroupskb/egress/stats")
int bpf_cgroup_egress(struct __sk_buff* skb) {
return bpf_traffic_account(skb, BPF_EGRESS);
}
-ELF_SEC(XT_BPF_EGRESS_PROG_NAME)
+SEC("skfilter/egress/xtbpf")
int xt_bpf_egress_prog(struct __sk_buff* skb) {
uint32_t key = skb->ifindex;
- bpf_update_stats(skb, IFACE_STATS_MAP, BPF_EGRESS, &key);
+ bpf_update_stats(skb, &iface_stats_map, BPF_EGRESS, &key);
return BPF_MATCH;
}
-ELF_SEC(XT_BPF_INGRESS_PROG_NAME)
+SEC("skfilter/ingress/xtbpf")
int xt_bpf_ingress_prog(struct __sk_buff* skb) {
uint32_t key = skb->ifindex;
- bpf_update_stats(skb, IFACE_STATS_MAP, BPF_INGRESS, &key);
+ bpf_update_stats(skb, &iface_stats_map, BPF_INGRESS, &key);
return BPF_MATCH;
}
-ELF_SEC(XT_BPF_WHITELIST_PROG_NAME)
+SEC("skfilter/whitelist/xtbpf")
int xt_bpf_whitelist_prog(struct __sk_buff* skb) {
uint32_t sock_uid = get_socket_uid(skb);
if (is_system_uid(sock_uid)) return BPF_MATCH;
- uint8_t* whitelistMatch = find_map_entry(UID_OWNER_MAP, &sock_uid);
+ uint8_t* whitelistMatch = find_map_entry(&uid_owner_map, &sock_uid);
if (whitelistMatch) return *whitelistMatch & HAPPY_BOX_MATCH;
return BPF_NOMATCH;
}
-ELF_SEC(XT_BPF_BLACKLIST_PROG_NAME)
+SEC("skfilter/blacklist/xtbpf")
int xt_bpf_blacklist_prog(struct __sk_buff* skb) {
uint32_t sock_uid = get_socket_uid(skb);
- uint8_t* blacklistMatch = find_map_entry(UID_OWNER_MAP, &sock_uid);
+ uint8_t* blacklistMatch = find_map_entry(&uid_owner_map, &sock_uid);
if (blacklistMatch) return *blacklistMatch & PENALTY_BOX_MATCH;
return BPF_NOMATCH;
}
+
+char _license[] SEC("license") = "Apache 2.0";
diff --git a/bpfloader/bpf_kern.h b/progs/netd.h
similarity index 65%
rename from bpfloader/bpf_kern.h
rename to progs/netd.h
index 25edbd4..6b2d103 100644
--- a/bpfloader/bpf_kern.h
+++ b/progs/netd.h
@@ -15,7 +15,7 @@
*/
/*
- * This h file together with bpf_kern.c is used for compiling the eBPF kernel
+ * This h file together with netd.c is used for compiling the eBPF kernel
* program.
*/
@@ -30,7 +30,7 @@
#include <stdint.h>
#include "netdbpf/bpf_shared.h"
-#define ELF_SEC(NAME) __attribute__((section(NAME), used))
+#define SEC(NAME) __attribute__((section(NAME), used))
struct uid_tag {
uint32_t uid;
@@ -51,11 +51,15 @@
uint64_t txBytes;
};
+struct IfaceValue {
+ char name[IFNAMSIZ];
+};
+
/* helper functions called from eBPF programs written in C */
-static void* (*find_map_entry)(uint64_t map, void* key) = (void*)BPF_FUNC_map_lookup_elem;
-static int (*write_to_map_entry)(uint64_t map, void* key, void* value,
+static void* (*find_map_entry)(void* map, void* key) = (void*)BPF_FUNC_map_lookup_elem;
+static int (*write_to_map_entry)(void* map, void* key, void* value,
uint64_t flags) = (void*)BPF_FUNC_map_update_elem;
-static int (*delete_map_entry)(uint64_t map, void* key) = (void*)BPF_FUNC_map_delete_elem;
+static int (*delete_map_entry)(void* map, void* key) = (void*)BPF_FUNC_map_delete_elem;
static uint64_t (*get_socket_cookie)(struct __sk_buff* skb) = (void*)BPF_FUNC_get_socket_cookie;
static uint32_t (*get_socket_uid)(struct __sk_buff* skb) = (void*)BPF_FUNC_get_socket_uid;
static int (*bpf_skb_load_bytes)(struct __sk_buff* skb, int off, void* to,
@@ -78,12 +82,85 @@
#define TCP_FLAG_OFF 13
#define RST_OFFSET 2
+/* loader usage */
+struct bpf_map_def {
+ unsigned int type;
+ unsigned int key_size;
+ unsigned int value_size;
+ unsigned int max_entries;
+ unsigned int map_flags;
+ unsigned int pad[2];
+};
+
+struct bpf_map_def SEC("maps") cookie_tag_map = {
+ .type = BPF_MAP_TYPE_HASH,
+ .key_size = sizeof(uint64_t),
+ .value_size = sizeof(struct uid_tag),
+ .max_entries = COOKIE_UID_MAP_SIZE,
+};
+
+struct bpf_map_def SEC("maps") uid_counterset_map = {
+ .type = BPF_MAP_TYPE_HASH,
+ .key_size = sizeof(uint32_t),
+ .value_size = sizeof(uint8_t),
+ .max_entries = UID_COUNTERSET_MAP_SIZE,
+};
+
+struct bpf_map_def SEC("maps") app_uid_stats_map = {
+ .type = BPF_MAP_TYPE_HASH,
+ .key_size = sizeof(uint32_t),
+ .value_size = sizeof(struct stats_value),
+ .max_entries = UID_STATS_MAP_SIZE,
+};
+
+struct bpf_map_def SEC("maps") uid_stats_map = {
+ .type = BPF_MAP_TYPE_HASH,
+ .key_size = sizeof(struct stats_key),
+ .value_size = sizeof(struct stats_value),
+ .max_entries = UID_STATS_MAP_SIZE,
+};
+
+struct bpf_map_def SEC("maps") tag_stats_map = {
+ .type = BPF_MAP_TYPE_HASH,
+ .key_size = sizeof(struct stats_key),
+ .value_size = sizeof(struct stats_value),
+ .max_entries = TAG_STATS_MAP_SIZE,
+};
+
+struct bpf_map_def SEC("maps") iface_stats_map = {
+ .type = BPF_MAP_TYPE_HASH,
+ .key_size = sizeof(uint32_t),
+ .value_size = sizeof(struct stats_value),
+ .max_entries = IFACE_STATS_MAP_SIZE,
+};
+
+struct bpf_map_def SEC("maps") configuration_map = {
+ .type = BPF_MAP_TYPE_HASH,
+ .key_size = sizeof(uint32_t),
+ .value_size = sizeof(uint8_t),
+ .max_entries = CONFIGURATION_MAP_SIZE,
+};
+
+struct bpf_map_def SEC("maps") uid_owner_map = {
+ .type = BPF_MAP_TYPE_HASH,
+ .key_size = sizeof(uint32_t),
+ .value_size = sizeof(uint8_t),
+ .max_entries = UID_OWNER_MAP_SIZE,
+};
+
+struct bpf_map_def SEC("maps") iface_index_name_map = {
+ .type = BPF_MAP_TYPE_HASH,
+ .key_size = sizeof(uint32_t),
+ .value_size = sizeof(struct IfaceValue),
+ .max_entries = IFACE_INDEX_NAME_MAP_SIZE,
+};
+
static __always_inline int is_system_uid(uint32_t uid) {
return (uid <= MAX_SYSTEM_UID) && (uid >= MIN_SYSTEM_UID);
}
-static __always_inline inline void bpf_update_stats(struct __sk_buff* skb, uint64_t map,
- int direction, void *key) {
+static __always_inline inline void bpf_update_stats(struct __sk_buff* skb, struct bpf_map_def* map,
+ int direction, void* key) {
struct stats_value* value;
value = find_map_entry(map, key);
if (!value) {
@@ -143,7 +220,7 @@
static __always_inline BpfConfig getConfig() {
uint32_t mapSettingKey = CONFIGURATION_KEY;
- BpfConfig* config = find_map_entry(CONFIGURATION_MAP, &mapSettingKey);
+ BpfConfig* config = find_map_entry(&configuration_map, &mapSettingKey);
if (!config) {
// Couldn't read configuration entry. Assume everything is disabled.
return DEFAULT_CONFIG;
@@ -161,7 +238,7 @@
return BPF_PASS;
}
- uint8_t* uidEntry = find_map_entry(UID_OWNER_MAP, &uid);
+ uint8_t* uidEntry = find_map_entry(&uid_owner_map, &uid);
uint8_t uidRules = uidEntry ? *uidEntry : 0;
if ((enabledRules & DOZABLE_MATCH) && !(uidRules & DOZABLE_MATCH)) {
return BPF_DROP;
@@ -185,7 +262,7 @@
}
uint64_t cookie = get_socket_cookie(skb);
- struct uid_tag* utag = find_map_entry(COOKIE_TAG_MAP, &cookie);
+ struct uid_tag* utag = find_map_entry(&cookie_tag_map, &cookie);
uint32_t uid, tag;
if (utag) {
uid = utag->uid;
@@ -197,15 +274,15 @@
struct stats_key key = {.uid = uid, .tag = tag, .counterSet = 0, .ifaceIndex = skb->ifindex};
- uint8_t* counterSet = find_map_entry(UID_COUNTERSET_MAP, &uid);
+ uint8_t* counterSet = find_map_entry(&uid_counterset_map, &uid);
if (counterSet) key.counterSet = (uint32_t)*counterSet;
if (tag) {
- bpf_update_stats(skb, TAG_STATS_MAP, direction, &key);
+ bpf_update_stats(skb, &tag_stats_map, direction, &key);
}
key.tag = 0;
- bpf_update_stats(skb, UID_STATS_MAP, direction, &key);
- bpf_update_stats(skb, APP_UID_STATS_MAP, direction, &uid);
+ bpf_update_stats(skb, &uid_stats_map, direction, &key);
+ bpf_update_stats(skb, &app_uid_stats_map, direction, &uid);
return match;
}