• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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