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