• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &section) {
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 &section : 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 &section) { 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 &section) -> 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 &section) -> 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 &section) -> 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