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