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}