106f6ba60Sopenharmony_ci/* 206f6ba60Sopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved. 306f6ba60Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 406f6ba60Sopenharmony_ci * you may not use this file except in compliance with the License. 506f6ba60Sopenharmony_ci * You may obtain a copy of the License at 606f6ba60Sopenharmony_ci * 706f6ba60Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 806f6ba60Sopenharmony_ci * 906f6ba60Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1006f6ba60Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1106f6ba60Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1206f6ba60Sopenharmony_ci * See the License for the specific language governing permissions and 1306f6ba60Sopenharmony_ci * limitations under the License. 1406f6ba60Sopenharmony_ci */ 1506f6ba60Sopenharmony_ci#include <malloc.h> 1606f6ba60Sopenharmony_ci#include "hook_socket_client.h" 1706f6ba60Sopenharmony_ci 1806f6ba60Sopenharmony_ci#include "common.h" 1906f6ba60Sopenharmony_ci#include "hook_common.h" 2006f6ba60Sopenharmony_ci#include "unix_socket_client.h" 2106f6ba60Sopenharmony_ci#include "share_memory_allocator.h" 2206f6ba60Sopenharmony_ci#include "logging.h" 2306f6ba60Sopenharmony_ci#include "sampling.h" 2406f6ba60Sopenharmony_ci#include <unistd.h> 2506f6ba60Sopenharmony_ci#include <sys/stat.h> 2606f6ba60Sopenharmony_ci#include <sys/types.h> 2706f6ba60Sopenharmony_ci#include <fcntl.h> 2806f6ba60Sopenharmony_ci#include <cstdio> 2906f6ba60Sopenharmony_ci#include <cstring> 3006f6ba60Sopenharmony_ci#include <iostream> 3106f6ba60Sopenharmony_ci 3206f6ba60Sopenharmony_cinamespace { 3306f6ba60Sopenharmony_ciconstexpr int FLUSH_FLAG = 20; 3406f6ba60Sopenharmony_cistd::atomic<uint64_t> g_flushCount = 0; 3506f6ba60Sopenharmony_cistd::atomic<bool> g_disableHook = false; 3606f6ba60Sopenharmony_ciconstexpr uint32_t MEMCHECK_DETAILINFO_MAXSIZE = 102400; 3706f6ba60Sopenharmony_ci 3806f6ba60Sopenharmony_cistruct OptArg { 3906f6ba60Sopenharmony_ci size_t pos; 4006f6ba60Sopenharmony_ci char *buf; 4106f6ba60Sopenharmony_ci}; 4206f6ba60Sopenharmony_ci 4306f6ba60Sopenharmony_ci} // namespace 4406f6ba60Sopenharmony_ci 4506f6ba60Sopenharmony_ci 4606f6ba60Sopenharmony_cistatic std::string GetRealTime() 4706f6ba60Sopenharmony_ci{ 4806f6ba60Sopenharmony_ci time_t now = time(nullptr); 4906f6ba60Sopenharmony_ci tm tm; 5006f6ba60Sopenharmony_ci const int timeLength = 64; 5106f6ba60Sopenharmony_ci char stampStr[timeLength] = {0}; 5206f6ba60Sopenharmony_ci 5306f6ba60Sopenharmony_ci if (localtime_r(&now, &tm) == nullptr || strftime(stampStr, timeLength, "%Y/%m/%d %H:%M:%S", &tm) == 0) { 5406f6ba60Sopenharmony_ci return "error time format!"; 5506f6ba60Sopenharmony_ci } 5606f6ba60Sopenharmony_ci return std::string(stampStr); 5706f6ba60Sopenharmony_ci} 5806f6ba60Sopenharmony_ci 5906f6ba60Sopenharmony_cistatic void NmdWriteStat(void *arg, const char *buf) 6006f6ba60Sopenharmony_ci{ 6106f6ba60Sopenharmony_ci struct OptArg *opt = static_cast<struct OptArg*>(arg); 6206f6ba60Sopenharmony_ci std::string getNmdTime = std::to_string(getpid()) + " " + GetRealTime() + "\n"; 6306f6ba60Sopenharmony_ci size_t nmdTimeLen = getNmdTime.size(); 6406f6ba60Sopenharmony_ci if (strncpy_s(opt->buf + opt->pos, MEMCHECK_DETAILINFO_MAXSIZE - opt->pos, 6506f6ba60Sopenharmony_ci getNmdTime.c_str(), nmdTimeLen) != EOK) { 6606f6ba60Sopenharmony_ci return; 6706f6ba60Sopenharmony_ci } 6806f6ba60Sopenharmony_ci opt->pos += nmdTimeLen; 6906f6ba60Sopenharmony_ci 7006f6ba60Sopenharmony_ci size_t len = strlen(buf); 7106f6ba60Sopenharmony_ci if (len + opt->pos + 1 > MEMCHECK_DETAILINFO_MAXSIZE) { 7206f6ba60Sopenharmony_ci return; 7306f6ba60Sopenharmony_ci } 7406f6ba60Sopenharmony_ci if (strncpy_s(opt->buf + opt->pos, MEMCHECK_DETAILINFO_MAXSIZE - opt->pos, buf, len) != EOK) { 7506f6ba60Sopenharmony_ci return; 7606f6ba60Sopenharmony_ci } 7706f6ba60Sopenharmony_ci opt->pos += len; 7806f6ba60Sopenharmony_ci} 7906f6ba60Sopenharmony_ci 8006f6ba60Sopenharmony_ciHookSocketClient::HookSocketClient(int pid, ClientConfig *config, Sampling *sampler, void (*disableHookCallback)()) 8106f6ba60Sopenharmony_ci : pid_(pid), config_(config), sampler_(sampler), disableHookCallback_(disableHookCallback) 8206f6ba60Sopenharmony_ci{ 8306f6ba60Sopenharmony_ci smbFd_ = 0; 8406f6ba60Sopenharmony_ci eventFd_ = 0; 8506f6ba60Sopenharmony_ci unixSocketClient_ = nullptr; 8606f6ba60Sopenharmony_ci serviceName_ = "HookService"; 8706f6ba60Sopenharmony_ci Connect(DEFAULT_UNIX_SOCKET_HOOK_FULL_PATH); 8806f6ba60Sopenharmony_ci} 8906f6ba60Sopenharmony_ci 9006f6ba60Sopenharmony_ciHookSocketClient::~HookSocketClient() 9106f6ba60Sopenharmony_ci{ 9206f6ba60Sopenharmony_ci if (stackWriter_) { 9306f6ba60Sopenharmony_ci stackWriter_->Flush(); 9406f6ba60Sopenharmony_ci } 9506f6ba60Sopenharmony_ci unixSocketClient_ = nullptr; 9606f6ba60Sopenharmony_ci stackWriter_ = nullptr; 9706f6ba60Sopenharmony_ci} 9806f6ba60Sopenharmony_ci 9906f6ba60Sopenharmony_cibool HookSocketClient::Connect(const std::string addrname) 10006f6ba60Sopenharmony_ci{ 10106f6ba60Sopenharmony_ci if (unixSocketClient_ != nullptr) { 10206f6ba60Sopenharmony_ci return false; 10306f6ba60Sopenharmony_ci } 10406f6ba60Sopenharmony_ci unixSocketClient_ = std::make_shared<UnixSocketClient>(); 10506f6ba60Sopenharmony_ci if (!unixSocketClient_->Connect(addrname, *this)) { 10606f6ba60Sopenharmony_ci unixSocketClient_ = nullptr; 10706f6ba60Sopenharmony_ci return false; 10806f6ba60Sopenharmony_ci } 10906f6ba60Sopenharmony_ci 11006f6ba60Sopenharmony_ci unixSocketClient_->SendHookConfig(reinterpret_cast<uint8_t *>(&pid_), sizeof(pid_)); 11106f6ba60Sopenharmony_ci return true; 11206f6ba60Sopenharmony_ci} 11306f6ba60Sopenharmony_ci 11406f6ba60Sopenharmony_cibool HookSocketClient::ProtocolProc(SocketContext &context, uint32_t pnum, const int8_t *buf, const uint32_t size) 11506f6ba60Sopenharmony_ci{ 11606f6ba60Sopenharmony_ci if (size != sizeof(ClientConfig)) { 11706f6ba60Sopenharmony_ci return true; 11806f6ba60Sopenharmony_ci } 11906f6ba60Sopenharmony_ci *config_ = *reinterpret_cast<ClientConfig *>(const_cast<int8_t*>(buf)); 12006f6ba60Sopenharmony_ci config_->maxStackDepth = config_->maxStackDepth > MAX_UNWIND_DEPTH ? MAX_UNWIND_DEPTH : config_->maxStackDepth; 12106f6ba60Sopenharmony_ci std::string configStr = config_->ToString(); 12206f6ba60Sopenharmony_ci sampler_->InitSampling(config_->sampleInterval); 12306f6ba60Sopenharmony_ci smbFd_ = context.ReceiveFileDiscriptor(); 12406f6ba60Sopenharmony_ci eventFd_ = context.ReceiveFileDiscriptor(); 12506f6ba60Sopenharmony_ci std::string smbName = "hooknativesmb_" + std::to_string(pid_); 12606f6ba60Sopenharmony_ci stackWriter_ = std::make_shared<StackWriter>(smbName, config_->shareMemorySize, 12706f6ba60Sopenharmony_ci smbFd_, eventFd_, config_->isBlocked); 12806f6ba60Sopenharmony_ci struct mallinfo2 mi = mallinfo2(); 12906f6ba60Sopenharmony_ci nmdType_ = config_->nmdType; 13006f6ba60Sopenharmony_ci if (nmdType_ == 0) { 13106f6ba60Sopenharmony_ci SendNmdInfo(); 13206f6ba60Sopenharmony_ci } 13306f6ba60Sopenharmony_ci return true; 13406f6ba60Sopenharmony_ci} 13506f6ba60Sopenharmony_ci 13606f6ba60Sopenharmony_cibool HookSocketClient::SendStack(const void* data, size_t size) 13706f6ba60Sopenharmony_ci{ 13806f6ba60Sopenharmony_ci if (stackWriter_ == nullptr || unixSocketClient_ == nullptr) { 13906f6ba60Sopenharmony_ci return false; 14006f6ba60Sopenharmony_ci } 14106f6ba60Sopenharmony_ci 14206f6ba60Sopenharmony_ci if (!unixSocketClient_->SendHeartBeat()) { 14306f6ba60Sopenharmony_ci return false; 14406f6ba60Sopenharmony_ci } 14506f6ba60Sopenharmony_ci 14606f6ba60Sopenharmony_ci stackWriter_->WriteTimeout(data, size); 14706f6ba60Sopenharmony_ci stackWriter_->Flush(); 14806f6ba60Sopenharmony_ci 14906f6ba60Sopenharmony_ci return true; 15006f6ba60Sopenharmony_ci} 15106f6ba60Sopenharmony_ci 15206f6ba60Sopenharmony_cibool HookSocketClient::SendStackWithPayload(const void* data, size_t size, const void* payload, 15306f6ba60Sopenharmony_ci size_t payloadSize) 15406f6ba60Sopenharmony_ci{ 15506f6ba60Sopenharmony_ci if (stackWriter_ == nullptr || unixSocketClient_ == nullptr || g_disableHook) { 15606f6ba60Sopenharmony_ci return false; 15706f6ba60Sopenharmony_ci } else if (unixSocketClient_->GetClientState() == CLIENT_STAT_THREAD_EXITED) { 15806f6ba60Sopenharmony_ci DisableHook(); 15906f6ba60Sopenharmony_ci return false; 16006f6ba60Sopenharmony_ci } 16106f6ba60Sopenharmony_ci 16206f6ba60Sopenharmony_ci bool ret = stackWriter_->WriteWithPayloadTimeout(data, size, payload, payloadSize, 16306f6ba60Sopenharmony_ci std::bind(&HookSocketClient::PeerIsConnected, this)); 16406f6ba60Sopenharmony_ci if (!ret && config_->isBlocked) { 16506f6ba60Sopenharmony_ci DisableHook(); 16606f6ba60Sopenharmony_ci return false; 16706f6ba60Sopenharmony_ci } 16806f6ba60Sopenharmony_ci ++g_flushCount; 16906f6ba60Sopenharmony_ci if (g_flushCount % FLUSH_FLAG == 0) { 17006f6ba60Sopenharmony_ci stackWriter_->Flush(); 17106f6ba60Sopenharmony_ci } 17206f6ba60Sopenharmony_ci return true; 17306f6ba60Sopenharmony_ci} 17406f6ba60Sopenharmony_ci 17506f6ba60Sopenharmony_civoid HookSocketClient::Flush() 17606f6ba60Sopenharmony_ci{ 17706f6ba60Sopenharmony_ci if (stackWriter_ == nullptr || unixSocketClient_ == nullptr) { 17806f6ba60Sopenharmony_ci return; 17906f6ba60Sopenharmony_ci } 18006f6ba60Sopenharmony_ci stackWriter_->Flush(); 18106f6ba60Sopenharmony_ci} 18206f6ba60Sopenharmony_ci 18306f6ba60Sopenharmony_civoid HookSocketClient::DisableHook() 18406f6ba60Sopenharmony_ci{ 18506f6ba60Sopenharmony_ci bool expected = false; 18606f6ba60Sopenharmony_ci if (g_disableHook.compare_exchange_strong(expected, true, std::memory_order_release, std::memory_order_relaxed)) { 18706f6ba60Sopenharmony_ci HILOG_BASE_INFO(LOG_CORE, "%s", __func__); 18806f6ba60Sopenharmony_ci if (disableHookCallback_) { 18906f6ba60Sopenharmony_ci disableHookCallback_(); 19006f6ba60Sopenharmony_ci } 19106f6ba60Sopenharmony_ci } 19206f6ba60Sopenharmony_ci} 19306f6ba60Sopenharmony_ci 19406f6ba60Sopenharmony_cibool HookSocketClient::PeerIsConnected() 19506f6ba60Sopenharmony_ci{ 19606f6ba60Sopenharmony_ci return !unixSocketClient_->IsConnected(); 19706f6ba60Sopenharmony_ci} 19806f6ba60Sopenharmony_ci 19906f6ba60Sopenharmony_cibool HookSocketClient::SendNmdInfo() 20006f6ba60Sopenharmony_ci{ 20106f6ba60Sopenharmony_ci if (!config_->printNmd) { 20206f6ba60Sopenharmony_ci return false; 20306f6ba60Sopenharmony_ci } 20406f6ba60Sopenharmony_ci void* nmdBuf = malloc(MEMCHECK_DETAILINFO_MAXSIZE); 20506f6ba60Sopenharmony_ci if (nmdBuf == nullptr) { 20606f6ba60Sopenharmony_ci return false; 20706f6ba60Sopenharmony_ci } 20806f6ba60Sopenharmony_ci struct OptArg opt = {0, reinterpret_cast<char*>(nmdBuf) }; 20906f6ba60Sopenharmony_ci malloc_stats_print(NmdWriteStat, &opt, "a"); 21006f6ba60Sopenharmony_ci StackRawData rawdata = {{{{0}}}}; 21106f6ba60Sopenharmony_ci rawdata.type = NMD_MSG; 21206f6ba60Sopenharmony_ci if (stackWriter_) { 21306f6ba60Sopenharmony_ci stackWriter_->WriteWithPayloadTimeout(&rawdata, sizeof(BaseStackRawData), 21406f6ba60Sopenharmony_ci reinterpret_cast<int8_t*>(opt.buf), strlen(opt.buf) + 1, 21506f6ba60Sopenharmony_ci std::bind(&HookSocketClient::PeerIsConnected, this)); 21606f6ba60Sopenharmony_ci } 21706f6ba60Sopenharmony_ci free(nmdBuf); 21806f6ba60Sopenharmony_ci return true; 21906f6ba60Sopenharmony_ci} 22006f6ba60Sopenharmony_ci 22106f6ba60Sopenharmony_cibool HookSocketClient::SendEndMsg() 22206f6ba60Sopenharmony_ci{ 22306f6ba60Sopenharmony_ci StackRawData rawdata = {{{{0}}}}; 22406f6ba60Sopenharmony_ci rawdata.type = END_MSG; 22506f6ba60Sopenharmony_ci if (stackWriter_) { 22606f6ba60Sopenharmony_ci stackWriter_->WriteTimeout(&rawdata, sizeof(BaseStackRawData)); 22706f6ba60Sopenharmony_ci } 22806f6ba60Sopenharmony_ci return true; 22906f6ba60Sopenharmony_ci}