1 /*
2 * Copyright (c) 2021 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 "hook_manager.h"
17
18 #include <limits>
19 #include <sys/stat.h>
20 #include <unistd.h>
21
22 #include "command_poller.h"
23 #include "common.h"
24 #include "epoll_event_poller.h"
25 #include "event_notifier.h"
26 #include "hook_common.h"
27 #include "hook_service.h"
28 #include "init_param.h"
29 #include "logging.h"
30 #include "plugin_service_types.pb.h"
31 #include "share_memory_allocator.h"
32 #include "utilities.h"
33 #include "virtual_runtime.h"
34 #include "hook_common.h"
35 #include "common.h"
36
37 using namespace OHOS::Developtools::NativeDaemon;
38
39 namespace {
40 const int DEFAULT_EVENT_POLLING_INTERVAL = 5000;
41 const int PAGE_BYTES = 4096;
42 std::shared_ptr<BufferWriter> g_buffWriter;
43 constexpr uint32_t MAX_BUFFER_SIZE = 10 * 1024;
44 const std::string STARTUP = "startup:";
45 const std::string PARAM_NAME = "libc.hook_mode";
46 const int MOVE_BIT_8 = 8;
47 const int MOVE_BIT_16 = 16;
48 const int MOVE_BIT_32 = 32;
49 const int SIGNAL_START_HOOK = 36;
50 const int SIGNAL_STOP_HOOK = 37;
51 const std::string VERSION = "1.01";
52 } // namespace
53
CheckProcess()54 bool HookManager::CheckProcess()
55 {
56 if (pid_ != 0) {
57 int ret = 0;
58 std::string pid_path = std::string();
59 struct stat stat_buf;
60 pid_path = "/proc/" + std::to_string(pid_) + "/status";
61 if (stat(pid_path.c_str(), &stat_buf) != 0) {
62 pid_ = 0;
63 HILOG_ERROR(LOG_CORE, "%s: hook process does not exist", __func__);
64 return false;
65 } else {
66 return true;
67 }
68 } else if (hookConfig_.process_name() != "") {
69 // check if the pid and process name is consistency
70 CheckProcessName();
71 }
72
73 return true;
74 }
75
CheckProcessName()76 void HookManager::CheckProcessName()
77 {
78 int pidValue = -1;
79 std::string processName = hookConfig_.process_name();
80 bool isExist = COMMON::IsProcessExist(processName, pidValue);
81 if (!isExist) {
82 HILOG_INFO(LOG_CORE, "Process %s not exist, set param", hookConfig_.process_name().c_str());
83 std::string cmd = STARTUP + hookConfig_.process_name();
84 int ret = SystemSetParameter(PARAM_NAME.c_str(), cmd.c_str());
85 if (ret < 0) {
86 HILOG_WARN(LOG_CORE, "set param failed, please manually set param and start process(%s)",
87 hookConfig_.process_name().c_str());
88 } else {
89 HILOG_INFO(LOG_CORE, "set param success, please start process(%s)", hookConfig_.process_name().c_str());
90 }
91 } else {
92 pid_ = pidValue;
93 HILOG_INFO(LOG_CORE, "Process %s exist, pid = %d", hookConfig_.process_name().c_str(), pid_);
94 }
95 }
96
HookManager()97 HookManager::HookManager() : buffer_(new (std::nothrow) uint8_t[MAX_BUFFER_SIZE]), pid_(0) { }
98
SetCommandPoller(const std::shared_ptr<CommandPoller> & p)99 void HookManager::SetCommandPoller(const std::shared_ptr<CommandPoller>& p)
100 {
101 commandPoller_ = p;
102 }
103
RegisterAgentPlugin(const std::string & pluginPath)104 bool HookManager::RegisterAgentPlugin(const std::string& pluginPath)
105 {
106 RegisterPluginRequest request;
107 request.set_request_id(commandPoller_->GetRequestId());
108 request.set_path(pluginPath);
109 request.set_sha256("");
110 request.set_name(pluginPath);
111 request.set_buffer_size_hint(0);
112 RegisterPluginResponse response;
113
114 if (commandPoller_->RegisterPlugin(request, response)) {
115 if (response.status() == ResponseStatus::OK) {
116 HILOG_DEBUG(LOG_CORE, "response.plugin_id() = %d", response.plugin_id());
117 agentIndex_ = response.plugin_id();
118 HILOG_DEBUG(LOG_CORE, "RegisterPlugin OK");
119 } else {
120 HILOG_DEBUG(LOG_CORE, "RegisterPlugin FAIL 1");
121 return false;
122 }
123 } else {
124 HILOG_DEBUG(LOG_CORE, "RegisterPlugin FAIL 2");
125 return false;
126 }
127
128 return true;
129 }
130
UnregisterAgentPlugin(const std::string & pluginPath)131 bool HookManager::UnregisterAgentPlugin(const std::string& pluginPath)
132 {
133 UnregisterPluginRequest request;
134 request.set_request_id(commandPoller_->GetRequestId());
135 request.set_plugin_id(agentIndex_);
136 UnregisterPluginResponse response;
137 if (commandPoller_->UnregisterPlugin(request, response)) {
138 if (response.status() != ResponseStatus::OK) {
139 HILOG_DEBUG(LOG_CORE, "UnregisterPlugin FAIL 1");
140 return false;
141 }
142 } else {
143 HILOG_DEBUG(LOG_CORE, "UnregisterPlugin FAIL 2");
144 return false;
145 }
146 agentIndex_ = -1;
147
148 return true;
149 }
150
LoadPlugin(const std::string & pluginPath)151 bool HookManager::LoadPlugin(const std::string& pluginPath)
152 {
153 return true;
154 }
155
UnloadPlugin(const std::string & pluginPath)156 bool HookManager::UnloadPlugin(const std::string& pluginPath)
157 {
158 return true;
159 }
160
UnloadPlugin(const uint32_t pluginId)161 bool HookManager::UnloadPlugin(const uint32_t pluginId)
162 {
163 return true;
164 }
165
CreatePluginSession(const std::vector<ProfilerPluginConfig> & config)166 bool HookManager::CreatePluginSession(const std::vector<ProfilerPluginConfig>& config)
167 {
168 HILOG_DEBUG(LOG_CORE, "CreatePluginSession");
169 UNUSED_PARAMETER(config);
170 smbName_ = "hooknativesmb";
171 // save config
172 std::string cfgData = config[0].config_data();
173 if (hookConfig_.ParseFromArray(reinterpret_cast<const uint8_t*>(cfgData.c_str()), cfgData.size()) <= 0) {
174 HILOG_ERROR(LOG_CORE, "%s: ParseFromArray failed", __func__);
175 return false;
176 }
177
178 if (getuid() != 0 && !COMMON::CheckApplicationPermission(hookConfig_.pid(), hookConfig_.process_name())) {
179 HILOG_ERROR(LOG_CORE, "Application debug permisson denied!");
180 return false;
181 }
182
183 pid_ = hookConfig_.pid();
184
185 int32_t uShortMax = (std::numeric_limits<unsigned short>::max)();
186 if (hookConfig_.filter_size() > uShortMax) {
187 HILOG_WARN(LOG_CORE, "%s: filter size invalid(size exceed 65535), reset to 65535!", __func__);
188 hookConfig_.set_filter_size(uShortMax);
189 }
190 if (!CheckProcess()) {
191 return false;
192 }
193
194 // create smb and eventNotifier
195 uint32_t bufferSize = hookConfig_.smb_pages() * PAGE_BYTES; /* bufferConfig.pages() */
196 shareMemoryBlock_ = ShareMemoryAllocator::GetInstance().CreateMemoryBlockLocal(smbName_, bufferSize);
197 CHECK_TRUE(shareMemoryBlock_ != nullptr, false, "CreateMemoryBlockLocal FAIL %s", smbName_.c_str());
198
199 eventNotifier_ = EventNotifier::Create(0, EventNotifier::NONBLOCK);
200 CHECK_NOTNULL(eventNotifier_, false, "create EventNotifier for %s failed!", smbName_.c_str());
201
202 // start event poller task
203 eventPoller_ = std::make_unique<EpollEventPoller>(DEFAULT_EVENT_POLLING_INTERVAL);
204 CHECK_NOTNULL(eventPoller_, false, "create event poller FAILED!");
205
206 eventPoller_->Init();
207 eventPoller_->Start();
208
209 eventPoller_->AddFileDescriptor(eventNotifier_->GetFd(), std::bind(&HookManager::ReadShareMemory, this));
210
211 HILOG_INFO(LOG_CORE, "hookservice smbFd = %d, eventFd = %d\n", shareMemoryBlock_->GetfileDescriptor(),
212 eventNotifier_->GetFd());
213
214 // hook config |F F F F F F F F F F F F F F F F|
215 // stack depth malloctype filtersize sharememory size
216
217 if (hookConfig_.max_stack_depth() == 0) {
218 // set default max depth
219 hookConfig_.set_max_stack_depth(MAX_UNWIND_DEPTH);
220 }
221 #if defined(__arm__)
222 hookConfig_.set_fp_unwind(false); // if OS is 32-bit,set fp_unwind false.
223 #endif
224 uint64_t hookConfig = (uint8_t)hookConfig_.max_stack_depth();
225 hookConfig <<= MOVE_BIT_8;
226
227 hookConfig |= hookConfig_.malloc_disable() ? MALLOCDISABLE : 0;
228 hookConfig |= hookConfig_.mmap_disable() ? MMAPDISABLE : 0;
229 hookConfig |= hookConfig_.free_stack_report() ? FREEMSGSTACK : 0;
230 hookConfig |= hookConfig_.munmap_stack_report() ? MUNMAPMSGSTACK : 0;
231 hookConfig |= hookConfig_.fp_unwind() ? FPUNWIND : 0;
232 hookConfig |= hookConfig_.blocked() ? BLOCKED : 0;
233
234 hookConfig <<= MOVE_BIT_16;
235 hookConfig |= hookConfig_.filter_size();
236 hookConfig <<= MOVE_BIT_32;
237 hookConfig |= bufferSize;
238
239 HILOG_INFO(LOG_CORE, "hookConfig filter size = %d, malloc disable = %d mmap disable = %d smb size = %u",
240 hookConfig_.filter_size(), hookConfig_.malloc_disable(), hookConfig_.mmap_disable(), bufferSize);
241 HILOG_INFO(LOG_CORE, "hookConfig fp unwind = %d, max stack depth = %d",
242 hookConfig_.fp_unwind(), hookConfig_.max_stack_depth());
243
244 hookService_ = std::make_shared<HookService>(shareMemoryBlock_->GetfileDescriptor(),
245 eventNotifier_->GetFd(), pid_, hookConfig_.process_name(), hookConfig);
246 CHECK_NOTNULL(hookService_, false, "HookService create failed!");
247
248 stackData_ = std::make_shared<StackDataRepeater>(STACK_DATA_SIZE);
249 CHECK_TRUE(stackData_ != nullptr, false, "Create StackDataRepeater FAIL");
250 stackPreprocess_ = std::make_shared<StackPreprocess>(stackData_, hookConfig_);
251 CHECK_TRUE(stackPreprocess_ != nullptr, false, "Create StackPreprocess FAIL");
252 stackPreprocess_->SetWriter(g_buffWriter);
253 return true;
254 }
255
ReadShareMemory()256 void HookManager::ReadShareMemory()
257 {
258 CHECK_NOTNULL(shareMemoryBlock_, NO_RETVAL, "smb is null!");
259 uint64_t value = eventNotifier_->Take();
260
261 while (true) {
262 auto rawStack = std::make_shared<StackDataRepeater::RawStack>();
263
264 bool ret = shareMemoryBlock_->TakeData([&](const int8_t data[], uint32_t size) -> bool {
265 if (size < sizeof(rawStack->stackConext)) {
266 HILOG_ERROR(LOG_CORE, "stack data invalid!");
267 return false;
268 }
269 if (memcpy_s(reinterpret_cast<void*>(&(rawStack->stackConext)), sizeof(rawStack->stackConext), data,
270 sizeof(rawStack->stackConext)) != EOK) {
271 HILOG_ERROR(LOG_CORE, "memcpy_s raw data failed!");
272 return false;
273 }
274 rawStack->reportFlag = true;
275 rawStack->reduceStackFlag = false;
276 rawStack->stackSize = size - sizeof(rawStack->stackConext);
277 if (rawStack->stackSize > 0) {
278 rawStack->stackData = std::make_unique<uint8_t[]>(rawStack->stackSize);
279 if (memcpy_s(rawStack->stackData.get(), rawStack->stackSize, data + sizeof(rawStack->stackConext),
280 rawStack->stackSize) != EOK) {
281 HILOG_ERROR(LOG_CORE, "memcpy_s stack data failed!");
282 }
283 }
284 return true;
285 });
286 if (!ret) {
287 break;
288 }
289 if (!stackData_->PutRawStack(rawStack)) {
290 break;
291 }
292 }
293 }
294
DestroyPluginSession(const std::vector<uint32_t> & pluginIds)295 bool HookManager::DestroyPluginSession(const std::vector<uint32_t>& pluginIds)
296 {
297 // release hook service
298 hookService_ = nullptr;
299
300 // stop event poller
301 if (eventPoller_) {
302 HILOG_ERROR(LOG_CORE, "eventPoller_ unset!");
303 eventPoller_->RemoveFileDescriptor(eventNotifier_->GetFd());
304 eventPoller_->Stop();
305 eventPoller_->Finalize();
306 eventPoller_ = nullptr;
307 }
308
309 // release smb and eventNotifier
310 if (shareMemoryBlock_) {
311 ShareMemoryAllocator::GetInstance().ReleaseMemoryBlockLocal(smbName_);
312 shareMemoryBlock_ = nullptr;
313 }
314
315 if (eventNotifier_) {
316 eventNotifier_ = nullptr;
317 }
318
319 stackPreprocess_ = nullptr;
320 stackData_ = nullptr;
321 return true;
322 }
323
StartPluginSession(const std::vector<uint32_t> & pluginIds,const std::vector<ProfilerPluginConfig> & config,PluginResult & result)324 bool HookManager::StartPluginSession(const std::vector<uint32_t>& pluginIds,
325 const std::vector<ProfilerPluginConfig>& config, PluginResult& result)
326 {
327 UNUSED_PARAMETER(config);
328 CHECK_TRUE(stackPreprocess_ != nullptr, false, "start StackPreprocess FAIL");
329 stackPreprocess_->StartTakeResults();
330
331 if (pid_ > 0) {
332 HILOG_INFO(LOG_CORE, "start command : send 36 signal to process %d", pid_);
333 if (kill(pid_, SIGNAL_START_HOOK) == -1) {
334 const int bufSize = 256;
335 char buf[bufSize] = {0};
336 strerror_r(errno, buf, bufSize);
337 HILOG_ERROR(LOG_CORE, "send 36 signal error = %s", buf);
338 }
339 } else {
340 HILOG_INFO(LOG_CORE, "StartPluginSession: pid_(%d) is less or equal zero.", pid_);
341 }
342
343 return true;
344 }
345
StopPluginSession(const std::vector<uint32_t> & pluginIds)346 bool HookManager::StopPluginSession(const std::vector<uint32_t>& pluginIds)
347 {
348 // send signal
349 if (pid_ == 0 && hookService_ != nullptr) {
350 pid_ = hookService_->GetPid();
351 }
352 if (pid_ > 0) {
353 HILOG_INFO(LOG_CORE, "stop command : send 37 signal to process %d", pid_);
354 if (kill(pid_, SIGNAL_STOP_HOOK) == -1) {
355 const int bufSize = 256;
356 char buf[bufSize] = {0};
357 strerror_r(errno, buf, bufSize);
358 HILOG_ERROR(LOG_CORE, "send 37 signal to process %d , error = %s", pid_, buf);
359 }
360 } else {
361 HILOG_INFO(LOG_CORE, "StopPluginSession: pid_(%d) is less or equal zero.", pid_);
362 }
363
364 CHECK_TRUE(stackPreprocess_ != nullptr, false, "stop StackPreprocess FAIL");
365 HILOG_INFO(LOG_CORE, "start StopTakeResults");
366 stackPreprocess_->StopTakeResults();
367
368 HILOG_INFO(LOG_CORE, "StopTakeResults success");
369
370 // make sure TakeResults thread exit
371 if (stackData_) {
372 stackData_->Close();
373 }
374 return true;
375 }
376
ReportPluginBasicData(const std::vector<uint32_t> & pluginIds)377 bool HookManager::ReportPluginBasicData(const std::vector<uint32_t>& pluginIds)
378 {
379 return true;
380 }
381
CreateWriter(std::string pluginName,uint32_t bufferSize,int smbFd,int eventFd)382 bool HookManager::CreateWriter(std::string pluginName, uint32_t bufferSize, int smbFd, int eventFd)
383 {
384 HILOG_DEBUG(LOG_CORE, "agentIndex_ %d", agentIndex_);
385 RegisterWriter(std::make_shared<BufferWriter>(pluginName, VERSION, bufferSize, smbFd, eventFd, agentIndex_));
386 return true;
387 }
388
ResetWriter(uint32_t pluginId)389 bool HookManager::ResetWriter(uint32_t pluginId)
390 {
391 RegisterWriter(nullptr);
392 return true;
393 }
394
RegisterWriter(const BufferWriterPtr & writer)395 void HookManager::RegisterWriter(const BufferWriterPtr& writer)
396 {
397 g_buffWriter = writer;
398 return;
399 }
400
SendProtobufPackage(uint8_t * cache,size_t length)401 bool HookManager::SendProtobufPackage(uint8_t *cache, size_t length)
402 {
403 if (g_buffWriter == nullptr) {
404 HILOG_ERROR(LOG_CORE, "HookManager:: BufferWriter empty, should set writer first");
405 return false;
406 }
407 ProfilerPluginData pluginData;
408 pluginData.set_name("nativehook");
409 pluginData.set_status(0);
410 pluginData.set_data(cache, length);
411
412 struct timespec ts;
413 clock_gettime(CLOCK_REALTIME, &ts);
414
415 pluginData.set_clock_id(ProfilerPluginData::CLOCKID_REALTIME);
416 pluginData.set_tv_sec(ts.tv_sec);
417 pluginData.set_tv_nsec(ts.tv_nsec);
418
419 g_buffWriter->WriteMessage(pluginData, "nativehook");
420 g_buffWriter->Flush();
421 return true;
422 }
423