1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <cerrno>
17 #include <fcntl.h>
18 #include <filesystem>
19 #include <functional>
20 #include <iostream>
21 #include <linux/bpf.h>
22 #include <linux/if_ether.h>
23 #include <arpa/inet.h>
24 #include <map>
25 #include <memory.h>
26 #include <string>
27 #include <sys/mount.h>
28 #include <sys/resource.h>
29 #include <sys/syscall.h>
30 #include <unistd.h>
31 #include <vector>
32
33 #include "bpf_def.h"
34 #include "bpf_loader.h"
35 #include "elf_types.hpp"
36 #include "elfio.hpp"
37 #include "elfio_relocation.hpp"
38 #include "net_manager_constants.h"
39 #include "netnative_log_wrapper.h"
40 #include "securec.h"
41
42 #define DEFINE_SECTION_NAME(name) \
43 { \
44 name, strlen(name) \
45 }
46
47 #define DEFINE_PROG_TYPE(progName, progType) \
48 { \
49 progName, progType \
50 }
51 #define DEFINE_ATTACH_TYPE(progName, attachType, needExpectedAttach) \
52 { \
53 progName, attachType, needExpectedAttach \
54 }
55
56 namespace OHOS::NetManagerStandard {
57 static constexpr const char *BPF_DIR = "/sys/fs/bpf";
58 static constexpr const char *CGROUP_DIR = "/sys/fs/cgroup";
59 static constexpr const char *MAPS_DIR = "/sys/fs/bpf/netsys/maps";
60 static constexpr const char *PROGS_DIR = "/sys/fs/bpf/netsys/progs";
61
62 // There is no limit to the size of SECTION_NAMES.
63 static const struct SectionName {
64 const char *sectionName;
65 size_t sectionNameLength;
66 } SECTION_NAMES[] = {
67 DEFINE_SECTION_NAME("kprobe/"),
68 DEFINE_SECTION_NAME("kretprobe/"),
69 DEFINE_SECTION_NAME("tracepoint/"),
70 DEFINE_SECTION_NAME("raw_tracepoint/"),
71 DEFINE_SECTION_NAME("xdp"),
72 DEFINE_SECTION_NAME("perf_event/"),
73 DEFINE_SECTION_NAME("socket"),
74 DEFINE_SECTION_NAME("cgroup/"),
75 DEFINE_SECTION_NAME("sockops"),
76 DEFINE_SECTION_NAME("sk_skb"),
77 DEFINE_SECTION_NAME("sk_msg"),
78 DEFINE_SECTION_NAME("cgroup_skb"),
79 DEFINE_SECTION_NAME("xdp_packet_parser"),
80 DEFINE_SECTION_NAME("schedcls"),
81 DEFINE_SECTION_NAME("classifier"),
82 DEFINE_SECTION_NAME("cgroup_sock"),
83 DEFINE_SECTION_NAME("cgroup_addr"),
84 };
85
86 static const constexpr struct {
87 const char *event;
88 bpf_prog_type progType;
89 } PROG_TYPES[] = {
90 DEFINE_PROG_TYPE("socket", BPF_PROG_TYPE_SOCKET_FILTER),
91 DEFINE_PROG_TYPE("cgroup_skb", BPF_PROG_TYPE_CGROUP_SKB),
92 DEFINE_PROG_TYPE("xdp", BPF_PROG_TYPE_XDP),
93 DEFINE_PROG_TYPE("xdp_packet_parser", BPF_PROG_TYPE_XDP),
94 DEFINE_PROG_TYPE("schedcls", BPF_PROG_TYPE_SCHED_CLS),
95 DEFINE_PROG_TYPE("classifier", BPF_PROG_TYPE_SCHED_CLS),
96 DEFINE_PROG_TYPE("cgroup_sock", BPF_PROG_TYPE_CGROUP_SOCK),
97 DEFINE_PROG_TYPE("cgroup_addr", BPF_PROG_TYPE_CGROUP_SOCK_ADDR),
98 };
99
100 static const constexpr struct {
101 const char *progName;
102 bpf_attach_type attachType;
103 bool needExpectedAttach;
104 } PROG_ATTACH_TYPES[] = {
105 DEFINE_ATTACH_TYPE("cgroup_sock_inet_create_socket", BPF_CGROUP_INET_SOCK_CREATE, false),
106 DEFINE_ATTACH_TYPE("cgroup_sock_inet_release_socket", BPF_CGROUP_INET_SOCK_RELEASE, true),
107 DEFINE_ATTACH_TYPE("cgroup_skb_uid_ingress", BPF_CGROUP_INET_INGRESS, false),
108 DEFINE_ATTACH_TYPE("cgroup_skb_uid_egress", BPF_CGROUP_INET_EGRESS, false),
109 DEFINE_ATTACH_TYPE("cgroup_addr_bind4", BPF_CGROUP_INET4_BIND, true),
110 DEFINE_ATTACH_TYPE("cgroup_addr_bind6", BPF_CGROUP_INET6_BIND, true),
111 DEFINE_ATTACH_TYPE("cgroup_addr_connect4", BPF_CGROUP_INET4_CONNECT, true),
112 DEFINE_ATTACH_TYPE("cgroup_addr_connect6", BPF_CGROUP_INET6_CONNECT, true),
113 DEFINE_ATTACH_TYPE("cgroup_addr_sendmsg4", BPF_CGROUP_UDP4_SENDMSG, true),
114 DEFINE_ATTACH_TYPE("cgroup_addr_sendmsg6", BPF_CGROUP_UDP6_SENDMSG, true),
115 };
116
117 int32_t g_sockFd = -1;
118
119 struct BpfMapData {
BpfMapDataOHOS::NetManagerStandard::BpfMapData120 BpfMapData() : fd(0)
121 {
122 if (memset_s(&def, sizeof(def), 0, sizeof(def)) != EOK) {
123 NETNATIVE_LOGE("memset_s error");
124 }
125 }
126
127 int32_t fd;
128 std::string name;
129 bpf_map_def def{};
130 };
131
PtrToU64(const type ptr)132 template <typename type> inline uint64_t PtrToU64(const type ptr)
133 {
134 return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(ptr));
135 }
136
EndsWith(const std::string & str,const std::string & searchFor)137 inline bool EndsWith(const std::string &str, const std::string &searchFor)
138 {
139 if (searchFor.size() > str.size()) {
140 return false;
141 }
142
143 std::string source = str.substr(str.size() - searchFor.size(), searchFor.size());
144 return source == searchFor;
145 }
146
SysBpf(bpf_cmd cmd,bpf_attr * attr,uint32_t size)147 inline int32_t SysBpf(bpf_cmd cmd, bpf_attr *attr, uint32_t size)
148 {
149 return static_cast<int32_t>(syscall(__NR_bpf, cmd, attr, size));
150 }
151
SysBpfObjGet(const std::string & pathName,uint32_t fileFlags)152 inline int32_t SysBpfObjGet(const std::string &pathName, uint32_t fileFlags)
153 {
154 bpf_attr attr = {};
155 if (memset_s(&attr, sizeof(attr), 0, sizeof(attr)) != EOK) {
156 return NETMANAGER_ERROR;
157 }
158 attr.pathname = PtrToU64(pathName.c_str());
159 attr.file_flags = fileFlags;
160 return SysBpf(BPF_OBJ_GET, &attr, sizeof(attr));
161 }
162
SysBpfObjPin(int32_t fd,const std::string & pathName)163 inline int32_t SysBpfObjPin(int32_t fd, const std::string &pathName)
164 {
165 bpf_attr attr = {};
166
167 if (memset_s(&attr, sizeof(attr), 0, sizeof(attr)) != EOK) {
168 return NETMANAGER_ERROR;
169 }
170 attr.pathname = PtrToU64(pathName.c_str());
171 if (fd < 0) {
172 return NETMANAGER_ERROR;
173 }
174 attr.bpf_fd = static_cast<uint32_t>(fd);
175
176 return SysBpf(BPF_OBJ_PIN, &attr, sizeof(attr));
177 }
178
SysBpfProgLoad(bpf_attr * attr,uint32_t size)179 inline int32_t SysBpfProgLoad(bpf_attr *attr, uint32_t size)
180 {
181 int32_t fd = SysBpf(BPF_PROG_LOAD, attr, size);
182 while (fd < 0 && errno == EAGAIN) {
183 fd = SysBpf(BPF_PROG_LOAD, attr, size);
184 }
185
186 return fd;
187 }
188
SysBpfObjDetach(bpf_attach_type type,const int progFd,const int cgFd)189 inline int32_t SysBpfObjDetach(bpf_attach_type type, const int progFd, const int cgFd)
190 {
191 bpf_attr attr = {};
192
193 if (memset_s(&attr, sizeof(attr), 0, sizeof(attr)) != EOK) {
194 return NETMANAGER_ERROR;
195 }
196 attr.target_fd = cgFd;
197 attr.attach_bpf_fd = progFd;
198 attr.attach_type = type;
199
200 return SysBpf(BPF_PROG_DETACH, &attr, sizeof(attr));
201 }
202
SysBpfObjAttach(bpf_attach_type type,const int progFd,const int cgFd)203 inline int32_t SysBpfObjAttach(bpf_attach_type type, const int progFd, const int cgFd)
204 {
205 bpf_attr attr = {};
206
207 if (memset_s(&attr, sizeof(attr), 0, sizeof(attr)) != EOK) {
208 return NETMANAGER_ERROR;
209 }
210 attr.target_fd = cgFd;
211 attr.attach_bpf_fd = progFd;
212 attr.attach_type = type;
213 attr.attach_flags = BPF_F_ALLOW_MULTI;
214
215 return SysBpf(BPF_PROG_ATTACH, &attr, sizeof(attr));
216 }
217
MatchSecName(const std::string & name)218 inline bool MatchSecName(const std::string &name)
219 {
220 auto matchFunc = [name](const SectionName &sec) -> bool {
221 if (name.size() < sec.sectionNameLength) {
222 return false;
223 }
224 return memcmp(name.c_str(), sec.sectionName, sec.sectionNameLength) == 0;
225 };
226 auto size = sizeof(SECTION_NAMES) / sizeof(SectionName);
227 return std::any_of(SECTION_NAMES, SECTION_NAMES + size, matchFunc);
228 }
229
UnPin(const std::string & path)230 inline int32_t UnPin(const std::string &path)
231 {
232 return unlink(path.c_str());
233 }
234
235 class ElfLoader {
236 public:
ElfLoader(std::string path)237 explicit ElfLoader(std::string path) : path_(std::move(path)), kernVersion_(0) {}
238
Unload() const239 ElfLoadError Unload() const
240 {
241 const struct {
242 uint32_t index;
243 const char *infoMsg;
244 std::function<ElfLoadError()> fun;
245 const char *errorMsg;
246 } funList[]{
247 {1, "path is valid", isPathValid_, "path is not valid"},
248 {2, "load elf file ok", loadElfFile_, "load elf file failed"},
249 {3, "load elf map section ok", loadElfMapsSection_, "load elf map section failed"},
250 {4, "delete maps ok", deleteMaps_, "delete maps failed"},
251 {5, "unload progs ok", unloadProgs_, "unload progs ok"},
252 };
253
254 for (const auto &fun : funList) {
255 auto ret = fun.fun();
256 if (ret != ELF_LOAD_ERR_NONE) {
257 NETNATIVE_LOGE("error msg is %{public}s", fun.errorMsg);
258 return static_cast<ElfLoadError>(ret);
259 }
260 NETNATIVE_LOGI("the %{public}u step: %{public}s", fun.index, fun.infoMsg);
261 }
262
263 return ELF_LOAD_ERR_NONE;
264 }
265
Load() const266 ElfLoadError Load() const
267 {
268 const struct {
269 uint32_t index;
270 const char *infoMsg;
271 std::function<ElfLoadError()> fun;
272 const char *errorMsg;
273 } funList[]{
274 {1, "path is valid", isPathValid_, "path is not valid"},
275 {2, "make directories fs ok", makeDirectories, "make directories fs failed"},
276 {3, "load elf file ok", loadElfFile_, "load elf file failed"},
277 {4, "version is valid", isVersionValid_, "version is not valid"},
278 {5, "set license and version ok", setLicenseAndVersion_, "set license and version failed"},
279 {6, "load elf map section ok", loadElfMapsSection_, "load elf map section failed"},
280 {7, "set rlimit ok", setRlimit_, "set rlimit failed"},
281 {8, "create maps ok", createMaps_, "create maps failed"},
282 {9, "parse relocation ok", parseRelocation_, "parse relocation failed"},
283 {10, "load progs ok", loadProgs_, "load progs failed"},
284 };
285 for (const auto &fun : funList) {
286 auto ret = fun.fun();
287 if (ret != ELF_LOAD_ERR_NONE) {
288 NETNATIVE_LOGE("error msg is %{public}s", fun.errorMsg);
289 return static_cast<ElfLoadError>(ret);
290 }
291 NETNATIVE_LOGI("the %{public}u step: %{public}s", fun.index, fun.infoMsg);
292 }
293
294 return ELF_LOAD_ERR_NONE;
295 }
296
297 private:
CheckPath()298 bool CheckPath()
299 {
300 if (path_.empty() || !std::filesystem::exists(path_) || std::filesystem::is_directory(path_)) {
301 return false;
302 }
303
304 return true;
305 }
306
IsPathValid()307 bool IsPathValid()
308 {
309 if (!CheckPath()) {
310 return false;
311 }
312 return EndsWith(path_, ".o");
313 }
314
LoadElfFile()315 bool LoadElfFile()
316 {
317 return elfIo_.load(path_);
318 }
319
IsVersionValid()320 bool IsVersionValid()
321 {
322 return elfIo_.get_version() == ELFIO::EV_CURRENT;
323 }
324
SetRlimit()325 static bool SetRlimit()
326 {
327 rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
328 return setrlimit(RLIMIT_MEMLOCK, &r) >= 0;
329 }
330
IsMounted(const std::string & dir)331 static bool IsMounted(const std::string &dir)
332 {
333 std::ifstream ifs("/proc/mounts", std::ios::in);
334 if (!ifs.is_open()) {
335 return false;
336 }
337
338 std::string s;
339 while (std::getline(ifs, s)) {
340 if (s.find(dir) != std::string::npos) {
341 ifs.close();
342 return true;
343 }
344 }
345 ifs.close();
346 return false;
347 }
348
MakeDir(const std::string & dir)349 static bool MakeDir(const std::string &dir)
350 {
351 if (std::filesystem::exists(dir) && std::filesystem::is_directory(dir)) {
352 return true;
353 }
354 if (!std::filesystem::exists(dir)) {
355 if (!std::filesystem::create_directories(std::filesystem::path(dir))) {
356 NETNATIVE_LOGE("filesystem make dir err %{public}d", errno);
357 return false;
358 }
359 return true;
360 }
361 if (!std::filesystem::is_directory(dir)) {
362 NETNATIVE_LOGE("%{public}s is a file", dir.c_str());
363 return false;
364 }
365 return true;
366 }
367
MakeDirectories()368 static bool MakeDirectories()
369 {
370 if (IsMounted(BPF_DIR) && std::filesystem::exists(MAPS_DIR) && std::filesystem::is_directory(MAPS_DIR) &&
371 std::filesystem::exists(PROGS_DIR) && std::filesystem::is_directory(PROGS_DIR)) {
372 NETNATIVE_LOGE("%{public}s", "bpf directories are exists");
373 return true;
374 }
375 if (!IsMounted(BPF_DIR) && mount(BPF_DIR, BPF_DIR, "bpf", MS_RELATIME, nullptr) < 0) {
376 NETNATIVE_LOGE("mount bpf fs failed: errno = %{public}d", errno);
377 return false;
378 }
379 if (!MakeDir(MAPS_DIR)) {
380 NETNATIVE_LOGE("can not make dir: %{public}s", MAPS_DIR);
381 return false;
382 }
383 if (!MakeDir(PROGS_DIR)) {
384 NETNATIVE_LOGE("can not make dir: %{public}s", PROGS_DIR);
385 return false;
386 }
387
388 if (!IsMounted(CGROUP_DIR) && mount(CGROUP_DIR, CGROUP_DIR, "cgroup2", MS_RELATIME, nullptr) < 0) {
389 NETNATIVE_LOGE("mount cgroup fs failed: errno = %{public}d", errno);
390 return false;
391 }
392 return true;
393 }
394
SetLicenseAndVersion()395 bool SetLicenseAndVersion()
396 {
397 return std::all_of(elfIo_.sections.begin(), elfIo_.sections.end(), [this](const auto §ion) {
398 if (section->get_name() == "license") {
399 license_ = section->get_data();
400 if (license_.empty()) {
401 return false;
402 }
403 } else if (section->get_name() == "version") {
404 try {
405 kernVersion_ = std::stoi(section->get_data());
406 } catch (const std::invalid_argument& e) {
407 NETNATIVE_LOGE("invalid_argument");
408 return false;
409 } catch (const std::out_of_range& e) {
410 NETNATIVE_LOGE("out_of_range");
411 return false;
412 }
413 if (kernVersion_ == 0) {
414 return false;
415 }
416 }
417
418 return true;
419 });
420 }
421
LoadElfMapSectionCore()422 std::map<ELFIO::Elf64_Addr, std::string> LoadElfMapSectionCore()
423 {
424 std::map<ELFIO::Elf64_Addr, std::string> mapName;
425 for (const auto §ion : elfIo_.sections) {
426 if (section->get_type() != ELFIO::SHT_SYMTAB && section->get_type() != ELFIO::SHT_DYNSYM) {
427 continue;
428 }
429 ELFIO::symbol_section_accessor symbols(elfIo_, section.get());
430 for (ELFIO::Elf_Xword i = 0; i < symbols.get_symbols_num(); i++) {
431 std::string name;
432 ELFIO::Elf64_Addr value = 0;
433 ELFIO::Elf_Xword size = 0;
434 unsigned char bind = 0;
435 unsigned char type = 0;
436 ELFIO::Elf_Half elfSection = 0;
437 unsigned char other = 0;
438 symbols.get_symbol(i, name, value, size, bind, type, elfSection, other);
439 if (type != ELFIO::STT_OBJECT || !EndsWith(name, "_map")) {
440 continue;
441 }
442 if (mapName.find(value) != mapName.end()) {
443 return {};
444 }
445 mapName[value] = name;
446 }
447 }
448 return mapName;
449 }
450
LoadElfMapsSection()451 bool LoadElfMapsSection()
452 {
453 if (elfIo_.sections.size() == 0) {
454 return false;
455 }
456
457 auto it = std::find_if(elfIo_.sections.begin(), elfIo_.sections.end(),
458 [](const auto §ion) { return section->get_name() == "maps"; });
459 if (it == elfIo_.sections.end()) {
460 return true;
461 }
462
463 ELFIO::section *mapsSection = it->get();
464 auto defs = reinterpret_cast<const bpf_map_def *>(mapsSection->get_data());
465 auto mapNum = mapsSection->get_size() / sizeof(bpf_map_def);
466 for (size_t i = 0; i < static_cast<size_t>(mapNum); i++) {
467 BpfMapData map;
468 map.def = defs[i];
469 maps_.emplace_back(map);
470 }
471 auto mapName = LoadElfMapSectionCore();
472 if (mapName.size() != maps_.size()) {
473 return false;
474 }
475 size_t mapIndex = 0;
476 for (const auto &[addr, name] : mapName) {
477 maps_[mapIndex].name = name;
478 ++mapIndex;
479 }
480
481 return true;
482 }
483
PrintMapAttr(const bpf_attr & attr)484 static void PrintMapAttr(const bpf_attr &attr)
485 {
486 NETNATIVE_LOGI("%{public}s", "BPF_MAP_CREATE:");
487 NETNATIVE_LOGI(" .map_type = %{public}u", attr.map_type);
488 NETNATIVE_LOGI(" .key_size = %{public}u", attr.key_size);
489 NETNATIVE_LOGI(" .value_size = %{public}u", attr.value_size);
490 NETNATIVE_LOGI(" .max_entries = %{public}u", attr.max_entries);
491 NETNATIVE_LOGI(" .map_flags = %{public}u", attr.map_flags);
492 NETNATIVE_LOGI(" .map_name = %{public}s", attr.map_name);
493 }
494
BpfCreateMapNode(const BpfMapData & map)495 static int32_t BpfCreateMapNode(const BpfMapData &map)
496 {
497 bpf_attr attr = {};
498 if (memset_s(&attr, sizeof(attr), 0, sizeof(attr)) != EOK) {
499 return NETMANAGER_ERROR;
500 }
501 attr.map_type = map.def.type;
502 attr.key_size = map.def.key_size;
503 attr.value_size = map.def.value_size;
504 attr.max_entries = map.def.max_entries;
505 attr.map_flags = map.def.map_flags;
506 if (!map.name.empty()) {
507 if (memcpy_s(attr.map_name, sizeof(attr.map_name) - 1, map.name.c_str(),
508 std::min<size_t>(map.name.size(), sizeof(attr.map_name) - 1)) != EOK) {
509 NETNATIVE_LOGE("Failed copy map name %{public}s", map.name.c_str());
510 return NETMANAGER_ERROR;
511 }
512 }
513 attr.numa_node = (map.def.map_flags & static_cast<unsigned int>(BPF_F_NUMA_NODE)) ? map.def.numa_node : 0;
514 PrintMapAttr(attr);
515
516 auto fd = SysBpf(BPF_MAP_CREATE, &attr, sizeof(attr));
517 if (fd < 0) {
518 NETNATIVE_LOGE("__NR_bpf, BPF_MAP_CREATE failed %{public}d %{public}d %{public}d", __NR_bpf, fd, errno);
519 }
520 return fd;
521 }
522
CreateMaps()523 bool CreateMaps()
524 {
525 for (auto &map : maps_) {
526 auto fd = BpfCreateMapNode(map);
527 if (fd < 0) {
528 NETNATIVE_LOGE("Failed create map (%{public}s): %{public}d", map.name.c_str(), fd);
529 return false;
530 }
531
532 map.fd = fd;
533 std::string mapPinLocation = std::string(MAPS_DIR) + "/" + map.name;
534 if (access(mapPinLocation.c_str(), F_OK) == 0) {
535 NETNATIVE_LOGI("map: %{public}s has already been pinned", mapPinLocation.c_str());
536 } else {
537 if (SysBpfObjPin(fd, mapPinLocation) < 0) {
538 NETNATIVE_LOGE("Failed to pin map: %{public}s, errno = %{public}d", mapPinLocation.c_str(), errno);
539 return false;
540 }
541 }
542 }
543 return true;
544 }
545
DeleteMaps()546 bool DeleteMaps()
547 {
548 return std::all_of(maps_.begin(), maps_.end(), [](const auto &map) {
549 std::string mapPinLocation = std::string(MAPS_DIR) + "/" + map.name;
550 if (access(mapPinLocation.c_str(), F_OK) == 0) {
551 auto ret = UnPin(mapPinLocation);
552 return ret >= 0;
553 }
554 return true;
555 });
556 }
557
ApplyRelocation(bpf_insn * insn,ELFIO::section * section) const558 bool ApplyRelocation(bpf_insn *insn, ELFIO::section *section) const
559 {
560 if (insn == nullptr || section == nullptr || section->get_entry_size() == 0) {
561 return false;
562 }
563
564 auto size = section->get_size() / section->get_entry_size();
565 if (size == 0) {
566 return false;
567 }
568
569 ELFIO::Elf64_Addr offset = 0;
570 ELFIO::Elf64_Addr symbolValue = 0;
571 std::string symbolName;
572 ELFIO::Elf_Word type = 0;
573 ELFIO::Elf_Sxword addend = 0;
574 ELFIO::Elf_Sxword calcValue = 0;
575 ELFIO::relocation_section_accessor relocation(elfIo_, section);
576 for (size_t i = 0; i < size; i++) {
577 relocation.get_entry(i, offset, symbolValue, symbolName, type, addend, calcValue);
578 uint32_t index = offset / sizeof(bpf_insn);
579 if (insn[index].code != (BPF_LD | BPF_IMM | BPF_DW)) {
580 NETNATIVE_LOGE("Invalid relo for insn[%{public}u].code 0x%{public}x 0x%{public}x", index,
581 insn[index].code, (BPF_LD | BPF_IMM | BPF_DW));
582 continue;
583 }
584
585 size_t mapIdx;
586 bool match = false;
587 for (mapIdx = 0; mapIdx < maps_.size(); mapIdx++) {
588 if (maps_[mapIdx].name == symbolName) {
589 match = true;
590 break;
591 }
592 }
593 if (!match) {
594 NETNATIVE_LOGE("Invalid relo for insn[%{public}u] no map_data match %{public}s index %{public}zu",
595 index, section->get_name().c_str(), i);
596 continue;
597 }
598 insn[index].src_reg = BPF_PSEUDO_MAP_FD;
599 insn[index].imm = maps_[mapIdx].fd;
600 }
601 return true;
602 }
603
BpfLoadProgram(std::string & progName,bpf_prog_type type,const bpf_insn * insns,size_t insnsCnt)604 int32_t BpfLoadProgram(std::string &progName, bpf_prog_type type, const bpf_insn *insns, size_t insnsCnt)
605 {
606 if (insns == nullptr) {
607 return NETMANAGER_ERROR;
608 }
609
610 bpf_attr attr = {};
611 if (memset_s(&attr, sizeof(attr), 0, sizeof(attr)) != EOK) {
612 return NETMANAGER_ERROR;
613 }
614 attr.prog_type = type;
615 if (kernVersion_ < 0) {
616 return NETMANAGER_ERROR;
617 }
618 attr.kern_version = static_cast<uint32_t>(kernVersion_);
619 attr.insn_cnt = static_cast<uint32_t>(insnsCnt);
620 attr.insns = PtrToU64(insns);
621 attr.license = PtrToU64(license_.c_str());
622 for (const auto &prog : PROG_ATTACH_TYPES) {
623 if (prog.progName != nullptr && progName == prog.progName) {
624 if (prog.needExpectedAttach) {
625 attr.expected_attach_type = prog.attachType;
626 }
627 break;
628 }
629 }
630
631 return SysBpfProgLoad(&attr, sizeof(attr));
632 }
633
ConvertEventToProgType(const std::string & event)634 static bpf_prog_type ConvertEventToProgType(const std::string &event)
635 {
636 for (const auto &prog : PROG_TYPES) {
637 size_t size = strlen(prog.event);
638 if (event.size() < size) {
639 continue;
640 }
641 if (memcmp(event.c_str(), prog.event, size) == 0) {
642 return prog.progType;
643 }
644 }
645 return static_cast<bpf_prog_type>(NETMANAGER_ERROR);
646 }
647
DoAttach(int32_t progFd,const std::string & progName)648 static bool DoAttach(int32_t progFd, const std::string &progName)
649 {
650 if (progName.size() < 1) {
651 NETNATIVE_LOGE("progName is null");
652 return false;
653 }
654 NETNATIVE_LOG_D("The progName = %{public}s", progName.c_str());
655
656 for (const auto &prog : PROG_ATTACH_TYPES) {
657 if (prog.progName != nullptr && progName == prog.progName) {
658 int cgroupFd = open(CGROUP_DIR, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
659 if (cgroupFd < 0) {
660 NETNATIVE_LOGE("open CGROUP_DIR failed: errno = %{public}d", errno);
661 return false;
662 }
663
664 if (SysBpfObjAttach(prog.attachType, progFd, cgroupFd) < NETSYS_SUCCESS) {
665 NETNATIVE_LOGE("attach %{pubic}s failed: errno = %{public}d", progName.c_str(), errno);
666 close(cgroupFd);
667 return false;
668 }
669
670 close(cgroupFd);
671 return true;
672 }
673 }
674
675 return true;
676 }
677
DoDetach(const std::string & progPinLocation,const std::string & progName)678 static void DoDetach(const std::string &progPinLocation, const std::string &progName)
679 {
680 if (progName.size() < 1) {
681 NETNATIVE_LOGE("progName is null");
682 return;
683 }
684 NETNATIVE_LOG_D("The progName = %{public}s", progName.c_str());
685
686 for (const auto &prog : PROG_ATTACH_TYPES) {
687 if (prog.progName != nullptr && progName == prog.progName) {
688 int cgroupFd = open(CGROUP_DIR, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
689 if (cgroupFd < NETSYS_SUCCESS) {
690 NETNATIVE_LOGE("open CGROUP_DIR failed: errno = %{public}d", errno);
691 return;
692 }
693
694 auto progFd = SysBpfObjGet(progPinLocation, 0);
695 if (progFd < NETSYS_SUCCESS) {
696 close(cgroupFd);
697 return;
698 }
699
700 if (SysBpfObjDetach(prog.attachType, progFd, cgroupFd) < NETSYS_SUCCESS) {
701 NETNATIVE_LOGE("detach %{pubic}s failed: errno = %{public}d", progName.c_str(), errno);
702 close(cgroupFd);
703 return;
704 }
705
706 close(cgroupFd);
707 return;
708 }
709 }
710 }
711
LoadProg(const std::string & event,const bpf_insn * insn,size_t insnCnt)712 bool LoadProg(const std::string &event, const bpf_insn *insn, size_t insnCnt)
713 {
714 auto progType = ConvertEventToProgType(event);
715 if (progType < NETSYS_SUCCESS) {
716 NETNATIVE_LOGE("unsupported program type: %{public}s", event.c_str());
717 return false;
718 }
719
720 if (insn == nullptr) {
721 NETNATIVE_LOGE("insn is null");
722 return false;
723 }
724
725 std::string progName = event;
726 std::replace(progName.begin(), progName.end(), '/', '_');
727 int32_t progFd = BpfLoadProgram(progName, progType, insn, insnCnt);
728 if (progFd < NETSYS_SUCCESS) {
729 NETNATIVE_LOGE("Failed to load bpf prog, error = %{public}d", errno);
730 return false;
731 }
732
733 std::string progPinLocation = std::string(PROGS_DIR) + "/" + progName;
734 if (access(progPinLocation.c_str(), F_OK) == 0) {
735 NETNATIVE_LOGI("prog: %{public}s has already been pinned", progPinLocation.c_str());
736 } else {
737 if (SysBpfObjPin(progFd, progPinLocation) < NETSYS_SUCCESS) {
738 NETNATIVE_LOGE("Failed to pin prog: %{public}s, errno = %{public}d", progPinLocation.c_str(), errno);
739 close(progFd);
740 return false;
741 }
742 }
743
744 /* attach socket filter */
745 if (progType == BPF_PROG_TYPE_SOCKET_FILTER) {
746 if (g_sockFd < 0) {
747 NETNATIVE_LOGE("create socket failed, %{public}d, err: %{public}d", g_sockFd, errno);
748 close(progFd);
749 /* return true to ignore this prog */
750 return true;
751 }
752 if (setsockopt(g_sockFd, SOL_SOCKET, SO_ATTACH_BPF, &progFd, sizeof(progFd)) < 0) {
753 NETNATIVE_LOGE("attach socket failed, err: %{public}d", errno);
754 close(g_sockFd);
755 g_sockFd = -1;
756 }
757 close(progFd);
758 return true;
759 } else {
760 auto ret = DoAttach(progFd, progName);
761 close(progFd);
762 return ret;
763 }
764 }
765
ParseRelocation()766 bool ParseRelocation()
767 {
768 return std::all_of(elfIo_.sections.begin(), elfIo_.sections.end(), [this](auto §ion) -> bool {
769 if (section->get_type() != ELFIO::SHT_REL) {
770 return true;
771 }
772
773 auto info = section->get_info();
774 auto progSec = elfIo_.sections[info];
775 if (progSec == nullptr) {
776 return true;
777 }
778
779 if (progSec->get_type() != ELFIO::SHT_PROGBITS || ((progSec->get_flags() & ELFIO::SHF_EXECINSTR) == 0)) {
780 return true;
781 }
782
783 auto insn = reinterpret_cast<bpf_insn *>(const_cast<char *>(progSec->get_data()));
784 if (insn == nullptr) {
785 return false;
786 }
787 if (!ApplyRelocation(insn, section.get())) {
788 return false;
789 }
790 return true;
791 });
792 }
793
UnloadProgs()794 bool UnloadProgs()
795 {
796 if (g_sockFd > 0) {
797 close(g_sockFd);
798 g_sockFd = -1;
799 }
800 return std::all_of(elfIo_.sections.begin(), elfIo_.sections.end(), [this](const auto §ion) -> bool {
801 if (!MatchSecName(section->get_name())) {
802 return true;
803 }
804
805 std::string progName = section->get_name();
806 std::replace(progName.begin(), progName.end(), '/', '_');
807 std::string progPinLocation = std::string(PROGS_DIR) + "/" + progName;
808 if (access(progPinLocation.c_str(), F_OK) == 0) {
809 DoDetach(progPinLocation, progName);
810
811 return UnPin(progPinLocation) < NETSYS_SUCCESS ? false : true;
812 }
813 return true;
814 });
815 }
816
LoadProgs()817 bool LoadProgs()
818 {
819 if (g_sockFd > 0) {
820 close(g_sockFd);
821 }
822 g_sockFd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
823 return std::all_of(elfIo_.sections.begin(), elfIo_.sections.end(), [this](const auto §ion) -> bool {
824 if (!MatchSecName(section->get_name())) {
825 return true;
826 }
827 return LoadProg(section->get_name(), reinterpret_cast<const bpf_insn *>(section->get_data()),
828 section->get_size() / sizeof(bpf_insn));
829 });
830 }
831
832 std::string path_;
833 ELFIO::elfio elfIo_;
834 std::string license_;
835 int32_t kernVersion_;
836 std::vector<BpfMapData> maps_;
837
__anon7cf7cb7f0c02() 838 std::function<ElfLoadError()> isPathValid_ = [this]() -> ElfLoadError {
839 if (!IsPathValid()) {
840 return ELF_LOAD_ERR_PATH_INVALID;
841 }
842 return ELF_LOAD_ERR_NONE;
843 };
844
__anon7cf7cb7f0d02() 845 std::function<ElfLoadError()> makeDirectories = []() -> ElfLoadError {
846 if (!MakeDirectories()) {
847 return ELF_LOAD_ERR_MAKE_DIR_FAIL;
848 }
849 return ELF_LOAD_ERR_NONE;
850 };
851
__anon7cf7cb7f0e02() 852 std::function<ElfLoadError()> loadElfFile_ = [this]() -> ElfLoadError {
853 if (!LoadElfFile()) {
854 return ELF_LOAD_ERR_LOAD_FILE_FAIL;
855 }
856 return ELF_LOAD_ERR_NONE;
857 };
858
__anon7cf7cb7f0f02() 859 std::function<ElfLoadError()> isVersionValid_ = [this]() -> ElfLoadError {
860 if (!IsVersionValid()) {
861 return ELF_LOAD_ERR_GET_VERSION_FAIL;
862 }
863 return ELF_LOAD_ERR_NONE;
864 };
865
__anon7cf7cb7f1002() 866 std::function<ElfLoadError()> setLicenseAndVersion_ = [this]() -> ElfLoadError {
867 if (!SetLicenseAndVersion()) {
868 return ELF_LOAD_ERR_SELECT_LICENSE_AND_VERSION_FAIL;
869 }
870 return ELF_LOAD_ERR_NONE;
871 };
872
__anon7cf7cb7f1102() 873 std::function<ElfLoadError()> loadElfMapsSection_ = [this]() -> ElfLoadError {
874 if (!LoadElfMapsSection()) {
875 return ELF_LOAD_ERR_LOAD_MAP_SECTION_FAIL;
876 }
877 return ELF_LOAD_ERR_NONE;
878 };
879
__anon7cf7cb7f1202() 880 std::function<ElfLoadError()> setRlimit_ = []() -> ElfLoadError {
881 if (!SetRlimit()) {
882 return ELF_LOAD_ERR_SET_RLIMIT_FAIL;
883 }
884 return ELF_LOAD_ERR_NONE;
885 };
886
__anon7cf7cb7f1302() 887 std::function<ElfLoadError()> createMaps_ = [this]() -> ElfLoadError {
888 if (!CreateMaps()) {
889 return ELF_LOAD_ERR_CREATE_MAP_FAIL;
890 }
891 return ELF_LOAD_ERR_NONE;
892 };
893
__anon7cf7cb7f1402() 894 std::function<ElfLoadError()> parseRelocation_ = [this]() -> ElfLoadError {
895 if (!ParseRelocation()) {
896 return ELF_LOAD_ERR_PARSE_RELOCATION_FAIL;
897 }
898 return ELF_LOAD_ERR_NONE;
899 };
900
__anon7cf7cb7f1502() 901 std::function<ElfLoadError()> loadProgs_ = [this]() -> ElfLoadError {
902 if (!LoadProgs()) {
903 return ELF_LOAD_ERR_LOAD_PROGS_FAIL;
904 }
905 return ELF_LOAD_ERR_NONE;
906 };
907
__anon7cf7cb7f1602() 908 std::function<ElfLoadError()> deleteMaps_ = [this]() -> ElfLoadError {
909 if (!DeleteMaps()) {
910 return ELF_LOAD_ERR_DELETE_MAP_FAIL;
911 }
912 return ELF_LOAD_ERR_NONE;
913 };
914
__anon7cf7cb7f1702() 915 std::function<ElfLoadError()> unloadProgs_ = [this]() -> ElfLoadError {
916 if (!UnloadProgs()) {
917 return ELF_LOAD_ERR_UNLOAD_PROGS_FAIL;
918 }
919 return ELF_LOAD_ERR_NONE;
920 };
921 };
922
LoadElf(const std::string & elfPath)923 ElfLoadError LoadElf(const std::string &elfPath)
924 {
925 ElfLoader loader(elfPath);
926 return loader.Load();
927 }
928
UnloadElf(const std::string & elfPath)929 ElfLoadError UnloadElf(const std::string &elfPath)
930 {
931 ElfLoader loader(elfPath);
932 return loader.Unload();
933 }
934 } // namespace OHOS::NetManagerStandard
935