1 /*
2 * Copyright (c) 2022 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 #ifdef ENABLE_ELFIO
17 #include "bpf_prog_loader.h"
18
19 #include "bpf_loader.h"
20 #include "bpf_map_creator.h"
21 #endif
22
23 namespace OHOS {
24 namespace Bpf {
25 #ifdef ENABLE_ELFIO
26 constexpr const char *CGROUP_DIR = "/sys/fs/cgroup";
27 constexpr const char *CGROUP_SKB_UID_INGRESS_PROG_NAME = "cgroup_skb_uid_ingress";
28 constexpr const char *CGROUP_SKB_UID_EGRESS_PROG_NAME = "cgroup_skb_uid_egress";
29 constexpr const int32_t BPF_LOG_BUF_SIZE = UINT32_MAX >> 8;
30
LoadAndAttach(const std::string & event,const bpf_insn * prog,int32_t size)31 bool BpfProgLoader::LoadAndAttach(const std::string &event, const bpf_insn *prog, int32_t size)
32 {
33 bpf_prog_type progType;
34 constexpr const char *SOCKET_NAME = "socket";
35 constexpr const char *CGROUP_SKB_NAME = "cgroup_skb";
36
37 if (!event.compare(0, strlen(SOCKET_NAME), SOCKET_NAME)) {
38 progType = BPF_PROG_TYPE_SOCKET_FILTER;
39 } else if (!event.compare(0, strlen(CGROUP_SKB_NAME), CGROUP_SKB_NAME)) {
40 progType = BPF_PROG_TYPE_CGROUP_SKB;
41 } else {
42 NETNATIVE_LOGE("Unknown event '%{public}s'", event.c_str());
43 return false;
44 }
45
46 std::string license(OHOS::Bpf::BpfLoader::GetInstance().GetLicense());
47 int32_t kernVer = OHOS::Bpf::BpfLoader::GetInstance().GetKernVersion();
48 size_t insnsCnt = size / sizeof(bpf_insn);
49
50 int32_t progFd = BpfLoadProg(progType, prog, insnsCnt, license, kernVer, bpfLogBuf_, BPF_LOG_BUF_SIZE);
51 if (progFd < 0) {
52 NETNATIVE_LOGE("Failed to load bpf prog, error = %{public}d", errno);
53 return false;
54 }
55 std::string progName = event;
56 replace(progName.begin(), progName.end(), '/', '_');
57 std::string progPinLocation = std::string("/sys/fs/bpf/prog_netsys_") + progName;
58 if (access(progPinLocation.c_str(), F_OK) == 0) {
59 NETNATIVE_LOGI("prog: %{public}s has already been pinned", progPinLocation.c_str());
60 } else {
61 if (SysBpfObjPin(progFd, progPinLocation)) {
62 NETNATIVE_LOGE("Failed to pin prog: %{public}s, errno = %{public}d", progPinLocation.c_str(), errno);
63 return false;
64 }
65 }
66
67 int cgroupFd = open(CGROUP_DIR, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
68 if (cgroupFd < 0) {
69 NETNATIVE_LOGE("open /sys/fs/cgroup failed, errno = %{public}d", errno);
70 return false;
71 }
72
73 if (CGROUP_SKB_UID_INGRESS_PROG_NAME == progName) {
74 if (SysBpfObjAttach(BPF_CGROUP_INET_INGRESS, progFd, cgroupFd) < 0) {
75 NETNATIVE_LOGE("Attach cgroup_skb_uid_ingress failed, errno = %{public}d", errno);
76 close(cgroupFd);
77 return false;
78 }
79 } else if (CGROUP_SKB_UID_EGRESS_PROG_NAME == progName) {
80 if (SysBpfObjAttach(BPF_CGROUP_INET_EGRESS, progFd, cgroupFd) < 0) {
81 NETNATIVE_LOGE("Attach cgroup_skb_uid_egress failed, errno = %{public}d", errno);
82 close(cgroupFd);
83 return false;
84 }
85 }
86 close(cgroupFd);
87 return true;
88 }
89
BpfLoadProg(bpf_prog_type type,const bpf_insn * insns,size_t insnsCnt,std::string & license,uint32_t kernVersion,std::string & logBuf,size_t logBufSz) const90 int32_t BpfProgLoader::BpfLoadProg(bpf_prog_type type, const bpf_insn *insns, size_t insnsCnt, std::string &license,
91 uint32_t kernVersion, std::string &logBuf, size_t logBufSz) const
92 {
93 BpfLoadProgAttr loadAttr;
94
95 (void)memset_s(&loadAttr, sizeof(BpfLoadProgAttr), '\0', sizeof(BpfLoadProgAttr));
96 loadAttr.progType = type;
97 loadAttr.expectedAttachType = BPF_CGROUP_INET_INGRESS;
98 loadAttr.insns = insns;
99 loadAttr.insnsCnt = insnsCnt;
100 loadAttr.license = license;
101 loadAttr.kernVersion = kernVersion;
102
103 return BpfLoadProgXattr(&loadAttr, logBuf, logBufSz);
104 }
105
InitProgAttr(const BpfLoadProgAttr * loadAttr,bpf_attr & attr,const std::string & logBuf,size_t logBufSz) const106 void BpfProgLoader::InitProgAttr(const BpfLoadProgAttr *loadAttr, bpf_attr &attr, const std::string &logBuf,
107 size_t logBufSz) const
108 {
109 (void)memset_s(&attr, sizeof(attr), 0, sizeof(attr));
110 attr.prog_type = loadAttr->progType;
111 attr.expected_attach_type = loadAttr->expectedAttachType;
112 attr.prog_ifindex = loadAttr->progIfindex;
113 attr.kern_version = loadAttr->kernVersion;
114 attr.insn_cnt = static_cast<uint32_t>(loadAttr->insnsCnt);
115 attr.insns = PtrToU64(loadAttr->insns);
116 attr.license = PtrToU64(loadAttr->license.c_str());
117
118 attr.log_level = loadAttr->logLevel;
119 if (loadAttr->logLevel) {
120 attr.log_buf = PtrToU64(logBuf.c_str());
121 attr.log_size = logBufSz;
122 } else {
123 attr.log_buf = PtrToU64(nullptr);
124 attr.log_size = 0;
125 }
126
127 attr.prog_btf_fd = loadAttr->progBtfFd;
128 attr.func_info_rec_size = loadAttr->funcInfoRecSize;
129 attr.func_info_cnt = loadAttr->funcInfoCnt;
130 attr.func_info = PtrToU64(loadAttr->funcInfo);
131 attr.line_info_rec_size = loadAttr->lineInfoRecSize;
132 attr.line_info_cnt = loadAttr->lineInfoCnt;
133 attr.line_info = PtrToU64(loadAttr->lineInfo);
134
135 if (!loadAttr->name.empty()) {
136 loadAttr->name.copy(attr.prog_name, (loadAttr->name.size() < (BPF_OBJ_NAME_LEN - 1) ? loadAttr->name.size()
137 : (BPF_OBJ_NAME_LEN - 1)));
138 }
139 attr.prog_flags = loadAttr->progFlags;
140 }
141
BpfLoadProgXattr(const BpfLoadProgAttr * loadAttr,std::string & logBuf,size_t logBufSz) const142 int32_t BpfProgLoader::BpfLoadProgXattr(const BpfLoadProgAttr *loadAttr, std::string &logBuf, size_t logBufSz) const
143 {
144 bpf_attr attr;
145
146 if (!loadAttr || !logBuf.empty() != !logBufSz) {
147 return -EINVAL;
148 }
149
150 if (loadAttr->logLevel && logBuf.empty()) {
151 return -EINVAL;
152 }
153
154 InitProgAttr(loadAttr, attr, logBuf, logBufSz);
155 return SysBpfProgLoad(&attr, sizeof(attr));
156 }
157 #endif
158 } // namespace Bpf
159 } // namespace OHOS
160