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 56namespace OHOS::NetManagerStandard { 57static constexpr const char *BPF_DIR = "/sys/fs/bpf"; 58static constexpr const char *CGROUP_DIR = "/sys/fs/cgroup"; 59static constexpr const char *MAPS_DIR = "/sys/fs/bpf/netsys/maps"; 60static constexpr const char *PROGS_DIR = "/sys/fs/bpf/netsys/progs"; 61 62// There is no limit to the size of SECTION_NAMES. 63static 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 86static 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 100static 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 117int32_t g_sockFd = -1; 118 119struct BpfMapData { 120 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 132template <typename type> inline uint64_t PtrToU64(const type ptr) 133{ 134 return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(ptr)); 135} 136 137inline 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 147inline 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 152inline 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 163inline 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 179inline 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 189inline 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 203inline 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 218inline 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 230inline int32_t UnPin(const std::string &path) 231{ 232 return unlink(path.c_str()); 233} 234 235class ElfLoader { 236public: 237 explicit ElfLoader(std::string path) : path_(std::move(path)), kernVersion_(0) {} 238 239 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 266 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 297private: 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 307 bool IsPathValid() 308 { 309 if (!CheckPath()) { 310 return false; 311 } 312 return EndsWith(path_, ".o"); 313 } 314 315 bool LoadElfFile() 316 { 317 return elfIo_.load(path_); 318 } 319 320 bool IsVersionValid() 321 { 322 return elfIo_.get_version() == ELFIO::EV_CURRENT; 323 } 324 325 static bool SetRlimit() 326 { 327 rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; 328 return setrlimit(RLIMIT_MEMLOCK, &r) >= 0; 329 } 330 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 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 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 395 bool SetLicenseAndVersion() 396 { 397 return std::all_of(elfIo_.sections.begin(), elfIo_.sections.end(), [this](const auto §ion) { 398 if (section->get_name() == "license") { 399 license_ = section->get_data(); 400 if (license_.empty()) { 401 return false; 402 } 403 } else if (section->get_name() == "version") { 404 try { 405 kernVersion_ = std::stoi(section->get_data()); 406 } catch (const std::invalid_argument& e) { 407 NETNATIVE_LOGE("invalid_argument"); 408 return false; 409 } catch (const std::out_of_range& e) { 410 NETNATIVE_LOGE("out_of_range"); 411 return false; 412 } 413 if (kernVersion_ == 0) { 414 return false; 415 } 416 } 417 418 return true; 419 }); 420 } 421 422 std::map<ELFIO::Elf64_Addr, std::string> LoadElfMapSectionCore() 423 { 424 std::map<ELFIO::Elf64_Addr, std::string> mapName; 425 for (const auto §ion : elfIo_.sections) { 426 if (section->get_type() != ELFIO::SHT_SYMTAB && section->get_type() != ELFIO::SHT_DYNSYM) { 427 continue; 428 } 429 ELFIO::symbol_section_accessor symbols(elfIo_, section.get()); 430 for (ELFIO::Elf_Xword i = 0; i < symbols.get_symbols_num(); i++) { 431 std::string name; 432 ELFIO::Elf64_Addr value = 0; 433 ELFIO::Elf_Xword size = 0; 434 unsigned char bind = 0; 435 unsigned char type = 0; 436 ELFIO::Elf_Half elfSection = 0; 437 unsigned char other = 0; 438 symbols.get_symbol(i, name, value, size, bind, type, elfSection, other); 439 if (type != ELFIO::STT_OBJECT || !EndsWith(name, "_map")) { 440 continue; 441 } 442 if (mapName.find(value) != mapName.end()) { 443 return {}; 444 } 445 mapName[value] = name; 446 } 447 } 448 return mapName; 449 } 450 451 bool LoadElfMapsSection() 452 { 453 if (elfIo_.sections.size() == 0) { 454 return false; 455 } 456 457 auto it = std::find_if(elfIo_.sections.begin(), elfIo_.sections.end(), 458 [](const auto §ion) { return section->get_name() == "maps"; }); 459 if (it == elfIo_.sections.end()) { 460 return true; 461 } 462 463 ELFIO::section *mapsSection = it->get(); 464 auto defs = reinterpret_cast<const bpf_map_def *>(mapsSection->get_data()); 465 auto mapNum = mapsSection->get_size() / sizeof(bpf_map_def); 466 for (size_t i = 0; i < static_cast<size_t>(mapNum); i++) { 467 BpfMapData map; 468 map.def = defs[i]; 469 maps_.emplace_back(map); 470 } 471 auto mapName = LoadElfMapSectionCore(); 472 if (mapName.size() != maps_.size()) { 473 return false; 474 } 475 size_t mapIndex = 0; 476 for (const auto &[addr, name] : mapName) { 477 maps_[mapIndex].name = name; 478 ++mapIndex; 479 } 480 481 return true; 482 } 483 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 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 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 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 558 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 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 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 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 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 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 766 bool ParseRelocation() 767 { 768 return std::all_of(elfIo_.sections.begin(), elfIo_.sections.end(), [this](auto §ion) -> bool { 769 if (section->get_type() != ELFIO::SHT_REL) { 770 return true; 771 } 772 773 auto info = section->get_info(); 774 auto progSec = elfIo_.sections[info]; 775 if (progSec == nullptr) { 776 return true; 777 } 778 779 if (progSec->get_type() != ELFIO::SHT_PROGBITS || ((progSec->get_flags() & ELFIO::SHF_EXECINSTR) == 0)) { 780 return true; 781 } 782 783 auto insn = reinterpret_cast<bpf_insn *>(const_cast<char *>(progSec->get_data())); 784 if (insn == nullptr) { 785 return false; 786 } 787 if (!ApplyRelocation(insn, section.get())) { 788 return false; 789 } 790 return true; 791 }); 792 } 793 794 bool UnloadProgs() 795 { 796 if (g_sockFd > 0) { 797 close(g_sockFd); 798 g_sockFd = -1; 799 } 800 return std::all_of(elfIo_.sections.begin(), elfIo_.sections.end(), [this](const auto §ion) -> bool { 801 if (!MatchSecName(section->get_name())) { 802 return true; 803 } 804 805 std::string progName = section->get_name(); 806 std::replace(progName.begin(), progName.end(), '/', '_'); 807 std::string progPinLocation = std::string(PROGS_DIR) + "/" + progName; 808 if (access(progPinLocation.c_str(), F_OK) == 0) { 809 DoDetach(progPinLocation, progName); 810 811 return UnPin(progPinLocation) < NETSYS_SUCCESS ? false : true; 812 } 813 return true; 814 }); 815 } 816 817 bool LoadProgs() 818 { 819 if (g_sockFd > 0) { 820 close(g_sockFd); 821 } 822 g_sockFd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 823 return std::all_of(elfIo_.sections.begin(), elfIo_.sections.end(), [this](const auto §ion) -> bool { 824 if (!MatchSecName(section->get_name())) { 825 return true; 826 } 827 return LoadProg(section->get_name(), reinterpret_cast<const bpf_insn *>(section->get_data()), 828 section->get_size() / sizeof(bpf_insn)); 829 }); 830 } 831 832 std::string path_; 833 ELFIO::elfio elfIo_; 834 std::string license_; 835 int32_t kernVersion_; 836 std::vector<BpfMapData> maps_; 837 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 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 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 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 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 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 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 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 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 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 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 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 923ElfLoadError LoadElf(const std::string &elfPath) 924{ 925 ElfLoader loader(elfPath); 926 return loader.Load(); 927} 928 929ElfLoadError UnloadElf(const std::string &elfPath) 930{ 931 ElfLoader loader(elfPath); 932 return loader.Unload(); 933} 934} // namespace OHOS::NetManagerStandard 935