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 &section) {
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 &section : 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 &section) { 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 &section) -> 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 &section) -> 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 &section) -> 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