• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved.
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 #include "hook_socket_client.h"
16 
17 #include "common.h"
18 #include "hook_common.h"
19 #include "unix_socket_client.h"
20 #include "share_memory_allocator.h"
21 #include "logging.h"
22 #include "sampling.h"
23 #include <unistd.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <fcntl.h>
27 #include <cstdio>
28 #include <cstdlib>
29 #include <cstring>
30 #include <iostream>
31 
32 namespace {
33 constexpr int FLUSH_FLAG = 20;
34 constexpr int ONLY_NMD_TYPE = 2;
35 constexpr int SIMP_NMD = 3;
36 std::atomic<uint64_t> g_flushCount = 0;
37 std::atomic<bool> g_disableHook = false;
38 constexpr uint32_t MEMCHECK_DETAILINFO_MAXSIZE = 102400;
39 
40 struct OptArg {
41     size_t pos;
42     char *buf;
43 };
44 
45 } // namespace
46 
47 
GetRealTime()48 static std::string GetRealTime()
49 {
50     time_t now = time(nullptr);
51     tm tm;
52     const int timeLength = 64;
53     char stampStr[timeLength] = {0};
54 
55     if (localtime_r(&now, &tm) == nullptr || strftime(stampStr, timeLength, "%Y/%m/%d %H:%M:%S", &tm) == 0) {
56         return "error time format!";
57     }
58     return std::string(stampStr);
59 }
60 
NmdWriteStat(void * arg,const char * buf)61 static void NmdWriteStat(void *arg, const char *buf)
62 {
63     struct OptArg *opt = static_cast<struct OptArg*>(arg);
64     std::string getNmdTime = std::to_string(getpid()) + " " + GetRealTime() + "\n";
65     size_t nmdTimeLen = getNmdTime.size();
66     if (strncpy_s(opt->buf + opt->pos, MEMCHECK_DETAILINFO_MAXSIZE - opt->pos,
67                   getNmdTime.c_str(), nmdTimeLen) != EOK) {
68         return;
69     }
70     opt->pos += nmdTimeLen;
71 
72     size_t len = strlen(buf);
73     if (len + opt->pos + 1 > MEMCHECK_DETAILINFO_MAXSIZE) {
74         return;
75     }
76     if (strncpy_s(opt->buf + opt->pos, MEMCHECK_DETAILINFO_MAXSIZE - opt->pos, buf, len) != EOK) {
77         return;
78     }
79     opt->pos += len;
80 }
81 
HookSocketClient(int pid,ClientConfig * config,Sampling * sampler,void (* disableHookCallback)())82 HookSocketClient::HookSocketClient(int pid, ClientConfig *config, Sampling *sampler, void (*disableHookCallback)())
83     : pid_(pid), config_(config), sampler_(sampler), disableHookCallback_(disableHookCallback)
84 {
85     smbFd_ = 0;
86     eventFd_ = 0;
87     unixSocketClient_ = nullptr;
88     serviceName_ = "HookService";
89     Connect(DEFAULT_UNIX_SOCKET_HOOK_FULL_PATH);
90 }
91 
~HookSocketClient()92 HookSocketClient::~HookSocketClient()
93 {
94     if (stackWriter_) {
95         stackWriter_->Flush();
96     }
97     unixSocketClient_ = nullptr;
98     stackWriter_ = nullptr;
99 }
100 
Connect(const std::string addrname)101 bool HookSocketClient::Connect(const std::string addrname)
102 {
103     if (unixSocketClient_ != nullptr) {
104         return false;
105     }
106     unixSocketClient_ = std::make_shared<UnixSocketClient>();
107     if (!unixSocketClient_->Connect(addrname, *this)) {
108         unixSocketClient_ = nullptr;
109         return false;
110     }
111 
112     unixSocketClient_->SendHookConfig(reinterpret_cast<uint8_t *>(&pid_), sizeof(pid_));
113     return true;
114 }
115 
ProtocolProc(SocketContext & context,uint32_t pnum,const int8_t * buf,const uint32_t size)116 bool HookSocketClient::ProtocolProc(SocketContext &context, uint32_t pnum, const int8_t *buf, const uint32_t size)
117 {
118     if (size != sizeof(ClientConfig)) {
119         return true;
120     }
121     *config_ = *reinterpret_cast<ClientConfig *>(const_cast<int8_t*>(buf));
122     config_->maxStackDepth  = config_->maxStackDepth > MAX_UNWIND_DEPTH ? MAX_UNWIND_DEPTH : config_->maxStackDepth;
123     std::string configStr = config_->ToString();
124     sampler_->InitSampling(config_->sampleInterval);
125     smbFd_ = context.ReceiveFileDiscriptor();
126     eventFd_ = context.ReceiveFileDiscriptor();
127     std::string smbName = "hooknativesmb_" + std::to_string(pid_);
128     stackWriter_ = std::make_shared<StackWriter>(smbName, config_->shareMemorySize,
129         smbFd_, eventFd_, config_->isBlocked, config_->isSaMode);
130     nmdType_ = config_->nmdType;
131     g_disableHook = false;
132     largestSize_ = config_->largestSize;
133     secondLargestSize_ = config_->secondLargestSize;
134     maxGrowthSize_ = config_->maxGrowthSize;
135     sampleInterval_ = config_->sampleInterval;
136     PROFILER_LOG_INFO(LOG_CORE, "HookSocketClient::ProtocolProc, ts1.1 = %d, ts1.2 = %d, ts2 = %d, ts3 = %d",
137         largestSize_, secondLargestSize_, maxGrowthSize_, sampleInterval_);
138     if (nmdType_ == 0 || nmdType_ == ONLY_NMD_TYPE) {
139         SendNmdInfo();
140     } else if (nmdType_ == SIMP_NMD) {
141         SendSimplifiedNmdInfo();
142     }
143     return true;
144 }
145 
SendStack(const void * data,size_t size)146 bool HookSocketClient::SendStack(const void* data, size_t size)
147 {
148     if (stackWriter_ == nullptr || unixSocketClient_ == nullptr) {
149         return false;
150     }
151 
152     if (!unixSocketClient_->SendHeartBeat()) {
153         return false;
154     }
155 
156     stackWriter_->WriteTimeout(data, size);
157     stackWriter_->Flush();
158 
159     return true;
160 }
161 
SendStackWithPayload(const void * data,size_t size,const void * payload,size_t payloadSize)162 bool HookSocketClient::SendStackWithPayload(const void* data, size_t size, const void* payload,
163     size_t payloadSize)
164 {
165     if (stackWriter_ == nullptr || unixSocketClient_ == nullptr || g_disableHook) {
166         return false;
167     } else if (unixSocketClient_->GetClientState() == CLIENT_STAT_THREAD_EXITED) {
168         DisableHook();
169         return false;
170     }
171 
172     bool ret = stackWriter_->WriteWithPayloadTimeout(data, size, payload, payloadSize,
173                                                      std::bind(&HookSocketClient::PeerIsConnected, this));
174     if (!ret && config_->isBlocked) {
175         DisableHook();
176         return false;
177     }
178     ++g_flushCount;
179     if (g_flushCount % FLUSH_FLAG == 0) {
180         stackWriter_->Flush();
181     }
182     return true;
183 }
184 
Flush()185 void HookSocketClient::Flush()
186 {
187     if (stackWriter_ == nullptr || unixSocketClient_ == nullptr) {
188         return;
189     }
190     stackWriter_->Flush();
191 }
192 
DisableHook()193 void HookSocketClient::DisableHook()
194 {
195     bool expected = false;
196     if (g_disableHook.compare_exchange_strong(expected, true, std::memory_order_release, std::memory_order_relaxed)) {
197         HILOG_BASE_INFO(LOG_CORE, "%s", __func__);
198         if (disableHookCallback_) {
199             disableHookCallback_();
200         }
201     }
202 }
203 
PeerIsConnected()204 bool HookSocketClient::PeerIsConnected()
205 {
206     return !unixSocketClient_->IsConnected();
207 }
208 
SendNmdInfo()209 bool HookSocketClient::SendNmdInfo()
210 {
211     if (!config_->printNmd) {
212         return false;
213     }
214     void* nmdBuf = malloc(MEMCHECK_DETAILINFO_MAXSIZE);
215     if (nmdBuf == nullptr) {
216         return false;
217     }
218     struct OptArg opt = {0, reinterpret_cast<char*>(nmdBuf) };
219     malloc_stats_print(NmdWriteStat, &opt, "a");
220     StackRawData rawdata = {{{{0}}}};
221     rawdata.type = NMD_MSG;
222     if (stackWriter_) {
223         stackWriter_->WriteWithPayloadTimeout(&rawdata, sizeof(BaseStackRawData),
224                                               reinterpret_cast<int8_t*>(opt.buf), strlen(opt.buf) + 1,
225                                               std::bind(&HookSocketClient::PeerIsConnected, this));
226     }
227     free(nmdBuf);
228     return true;
229 }
230 
SendSimplifiedNmdInfo()231 bool HookSocketClient::SendSimplifiedNmdInfo()
232 {
233     if (!config_->printNmd) {
234         return false;
235     }
236     void* nmdBuf = malloc(MEMCHECK_DETAILINFO_MAXSIZE);
237     if (nmdBuf == nullptr) {
238         return false;
239     }
240     struct OptArg opt = {0, reinterpret_cast<char*>(nmdBuf) };
241     malloc_stats_print(NmdWriteStat, &opt, "s");
242     StackRawData rawdata = {{{{0}}}};
243     rawdata.type = NMD_MSG;
244     if (stackWriter_) {
245         stackWriter_->WriteWithPayloadTimeout(&rawdata, sizeof(BaseStackRawData),
246                                               reinterpret_cast<int8_t*>(opt.buf), strlen(opt.buf) + 1,
247                                               std::bind(&HookSocketClient::PeerIsConnected, this));
248     }
249     stackWriter_->Flush();
250     free(nmdBuf);
251     return true;
252 }
253 
SendEndMsg()254 bool HookSocketClient::SendEndMsg()
255 {
256     StackRawData rawdata = {{{{0}}}};
257     rawdata.type = END_MSG;
258     if (stackWriter_) {
259         stackWriter_->WriteTimeout(&rawdata, sizeof(BaseStackRawData));
260     }
261     return true;
262 }