• 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 #include "daemon.h"
16 #ifndef TEST_HASH
17 #include "hdc_hash_gen.h"
18 #endif
19 #include "../common/serial_struct.h"
20 #include <openssl/sha.h>
21 
22 namespace Hdc {
23 #ifdef USE_CONFIG_UV_THREADS
HdcDaemon(bool serverOrDaemonIn,size_t uvThreadSize)24 HdcDaemon::HdcDaemon(bool serverOrDaemonIn, size_t uvThreadSize)
25     : HdcSessionBase(serverOrDaemonIn, uvThreadSize)
26 #else
27 HdcDaemon::HdcDaemon(bool serverOrDaemonIn)
28     : HdcSessionBase(serverOrDaemonIn, -1)
29 #endif
30 {
31     clsTCPServ = nullptr;
32     clsUSBServ = nullptr;
33 #ifdef HDC_SUPPORT_UART
34     clsUARTServ = nullptr;
35 #endif
36     clsJdwp = nullptr;
37     enableSecure = false;
38 }
39 
~HdcDaemon()40 HdcDaemon::~HdcDaemon()
41 {
42     WRITE_LOG(LOG_DEBUG, "~HdcDaemon");
43 }
44 
ClearInstanceResource()45 void HdcDaemon::ClearInstanceResource()
46 {
47     TryStopInstance();
48     Base::TryCloseLoop(&loopMain, "HdcDaemon::~HdcDaemon");
49     if (clsTCPServ) {
50         delete (HdcDaemonTCP *)clsTCPServ;
51         clsTCPServ = nullptr;
52     }
53     if (clsUSBServ) {
54         delete (HdcDaemonUSB *)clsUSBServ;
55         clsUSBServ = nullptr;
56     }
57 #ifdef HDC_SUPPORT_UART
58     if (clsUARTServ) {
59         delete (HdcDaemonUART *)clsUARTServ;
60     }
61     clsUARTServ = nullptr;
62 #endif
63     if (clsJdwp) {
64         delete (HdcJdwp *)clsJdwp;
65         clsJdwp = nullptr;
66     }
67     WRITE_LOG(LOG_DEBUG, "~HdcDaemon finish");
68 }
69 
TryStopInstance()70 void HdcDaemon::TryStopInstance()
71 {
72     ClearSessions();
73     if (clsTCPServ) {
74         WRITE_LOG(LOG_DEBUG, "Stop TCP");
75         ((HdcDaemonTCP *)clsTCPServ)->Stop();
76     }
77     if (clsUSBServ) {
78         WRITE_LOG(LOG_DEBUG, "Stop USB");
79         ((HdcDaemonUSB *)clsUSBServ)->Stop();
80     }
81 #ifdef HDC_SUPPORT_UART
82     if (clsUARTServ) {
83         WRITE_LOG(LOG_DEBUG, "Stop UART");
84         ((HdcDaemonUART *)clsUARTServ)->Stop();
85     }
86 #endif
87     ((HdcJdwp *)clsJdwp)->Stop();
88     // workaround temply remove MainLoop instance clear
89     ReMainLoopForInstanceClear();
90     WRITE_LOG(LOG_DEBUG, "Stop loopmain");
91 }
92 
93 #ifdef HDC_SUPPORT_UART
InitMod(bool bEnableTCP,bool bEnableUSB,bool bEnableUART)94 void HdcDaemon::InitMod(bool bEnableTCP, bool bEnableUSB, [[maybe_unused]] bool bEnableUART)
95 #else
96 void HdcDaemon::InitMod(bool bEnableTCP, bool bEnableUSB)
97 #endif
98 {
99     WRITE_LOG(LOG_DEBUG, "HdcDaemon InitMod");
100 #ifdef HDC_SUPPORT_UART
101     WRITE_LOG(LOG_DEBUG, "bEnableTCP:%d,bEnableUSB:%d", bEnableTCP, bEnableUSB);
102 #endif
103     if (bEnableTCP) {
104         // tcp
105         clsTCPServ = new(std::nothrow) HdcDaemonTCP(false, this);
106         if (clsTCPServ == nullptr) {
107             WRITE_LOG(LOG_FATAL, "InitMod new clsTCPServ failed");
108             return;
109         }
110         ((HdcDaemonTCP *)clsTCPServ)->Initial();
111     }
112     if (bEnableUSB) {
113         // usb
114         clsUSBServ = new(std::nothrow) HdcDaemonUSB(false, this);
115         if (clsUSBServ == nullptr) {
116             WRITE_LOG(LOG_FATAL, "InitMod new clsUSBServ failed");
117             return;
118         }
119         ((HdcDaemonUSB *)clsUSBServ)->Initial();
120     }
121 #ifdef HDC_SUPPORT_UART
122     WRITE_LOG(LOG_DEBUG, "bEnableUART:%d", bEnableUART);
123     if (bEnableUART) {
124         // UART
125         clsUARTServ = new(std::nothrow) HdcDaemonUART(*this);
126         if (clsUARTServ == nullptr) {
127             WRITE_LOG(LOG_FATAL, "InitMod new clsUARTServ failed");
128             return;
129         }
130         ((HdcDaemonUART *)clsUARTServ)->Initial();
131     }
132 #endif
133     clsJdwp = new(std::nothrow) HdcJdwp(&loopMain);
134     if (clsJdwp == nullptr) {
135         WRITE_LOG(LOG_FATAL, "InitMod new clsJdwp failed");
136         return;
137     }
138     ((HdcJdwp *)clsJdwp)->Initial();
139     // enable security
140     string secure;
141     SystemDepend::GetDevItem("ro.hdc.secure", secure);
142     enableSecure = (Base::Trim(secure) == "1");
143 }
144 
145 // clang-format off
RedirectToTask(HTaskInfo hTaskInfo,HSession hSession,const uint32_t channelId,const uint16_t command,uint8_t * payload,const int payloadSize)146 bool HdcDaemon::RedirectToTask(HTaskInfo hTaskInfo, HSession hSession, const uint32_t channelId,
147                                const uint16_t command, uint8_t *payload, const int payloadSize)
148 {
149     StartTraceScope("HdcDaemon::RedirectToTask");
150     bool ret = true;
151     hTaskInfo->ownerSessionClass = this;
152     switch (command) {
153         case CMD_UNITY_EXECUTE:
154         case CMD_UNITY_REMOUNT:
155         case CMD_UNITY_REBOOT:
156         case CMD_UNITY_RUNMODE:
157         case CMD_UNITY_HILOG:
158         case CMD_UNITY_ROOTRUN:
159         case CMD_UNITY_TERMINATE:
160         case CMD_UNITY_BUGREPORT_INIT:
161         case CMD_JDWP_LIST:
162         case CMD_JDWP_TRACK:
163             ret = TaskCommandDispatch<HdcDaemonUnity>(hTaskInfo, TYPE_UNITY, command, payload, payloadSize);
164             break;
165         case CMD_SHELL_INIT:
166         case CMD_SHELL_DATA:
167             ret = TaskCommandDispatch<HdcShell>(hTaskInfo, TYPE_SHELL, command, payload, payloadSize);
168             break;
169         case CMD_FILE_CHECK:
170         case CMD_FILE_DATA:
171         case CMD_FILE_FINISH:
172         case CMD_FILE_INIT:
173         case CMD_FILE_BEGIN:
174         case CMD_FILE_MODE:
175         case CMD_DIR_MODE:
176             ret = TaskCommandDispatch<HdcFile>(hTaskInfo, TASK_FILE, command, payload, payloadSize);
177             break;
178         // One-way function, so fewer options
179         case CMD_APP_CHECK:
180         case CMD_APP_DATA:
181         case CMD_APP_UNINSTALL:
182             ret = TaskCommandDispatch<HdcDaemonApp>(hTaskInfo, TASK_APP, command, payload, payloadSize);
183             break;
184         case CMD_FORWARD_INIT:
185         case CMD_FORWARD_CHECK:
186         case CMD_FORWARD_ACTIVE_MASTER:
187         case CMD_FORWARD_ACTIVE_SLAVE:
188         case CMD_FORWARD_DATA:
189         case CMD_FORWARD_FREE_CONTEXT:
190         case CMD_FORWARD_CHECK_RESULT:
191             ret = TaskCommandDispatch<HdcDaemonForward>(hTaskInfo, TASK_FORWARD, command, payload, payloadSize);
192             break;
193         default:
194         // ignore unknown command
195             break;
196     }
197     return ret;
198 }
199 // clang-format on
200 
HandDaemonAuth(HSession hSession,const uint32_t channelId,SessionHandShake & handshake)201 bool HdcDaemon::HandDaemonAuth(HSession hSession, const uint32_t channelId, SessionHandShake &handshake)
202 {
203     bool ret = false;
204     switch (handshake.authType) {
205         case AUTH_NONE: {  // AUTH_NONE -> AUTH
206             hSession->tokenRSA = Base::GetRandomString(SHA_DIGEST_LENGTH);
207             handshake.authType = AUTH_TOKEN;
208             handshake.buf = hSession->tokenRSA;
209             string bufString = SerialStruct::SerializeToString(handshake);
210             Send(hSession->sessionId, channelId, CMD_KERNEL_HANDSHAKE,
211                  reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())),
212                  bufString.size());
213             ret = true;
214             break;
215         }
216         case AUTH_SIGNATURE: {
217             // When Host is first connected to the device, the signature authentication is inevitable, and the
218             // certificate verification must be triggered.
219             //
220             // When the certificate is verified, the client sends a public key to the device, triggered the system UI
221             // jump out dialog, and click the system, the system will store the Host public key certificate in the
222             // device locally, and the signature authentication will be correct when the subsequent connection is
223             // connected.
224             if (!HdcAuth::AuthVerify(reinterpret_cast<uint8_t *>(const_cast<char *>(hSession->tokenRSA.c_str())),
225                 reinterpret_cast<uint8_t *>(const_cast<char *>(handshake.buf.c_str())), handshake.buf.size())) {
226                 // Next auth
227                 handshake.authType = AUTH_TOKEN;
228                 handshake.buf = hSession->tokenRSA;
229                 string bufString = SerialStruct::SerializeToString(handshake);
230                 Send(hSession->sessionId, channelId, CMD_KERNEL_HANDSHAKE,
231                      reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())), bufString.size());
232                 break;
233             }
234             ret = true;
235             break;
236         }
237         case AUTH_PUBLICKEY: {
238             ret = HdcAuth::PostUIConfirm(handshake.buf);
239             WRITE_LOG(LOG_DEBUG, "Auth host OK, postUIConfirm");
240             break;
241         }
242         default:
243             break;
244     }
245     return ret;
246 }
247 
DaemonSessionHandshake(HSession hSession,const uint32_t channelId,uint8_t * payload,int payloadSize)248 bool HdcDaemon::DaemonSessionHandshake(HSession hSession, const uint32_t channelId, uint8_t *payload, int payloadSize)
249 {
250     StartTraceScope("HdcDaemon::DaemonSessionHandshake");
251     // session handshake step2
252     string s = string(reinterpret_cast<char *>(payload), payloadSize);
253     SessionHandShake handshake;
254     string err;
255     SerialStruct::ParseFromString(handshake, s);
256 #ifdef HDC_DEBUG
257     WRITE_LOG(LOG_DEBUG, "session %s try to handshake", hSession->ToDebugString().c_str());
258 #endif
259     // banner to check is parse ok...
260     if (handshake.banner != HANDSHAKE_MESSAGE) {
261         hSession->availTailIndex = 0;
262         WRITE_LOG(LOG_FATAL, "Recv server-hello failed");
263         return false;
264     }
265     if (handshake.authType == AUTH_NONE) {
266         // daemon handshake 1st packet
267         uint32_t unOld = hSession->sessionId;
268         hSession->sessionId = handshake.sessionId;
269         hSession->connectKey = handshake.connectKey;
270         AdminSession(OP_UPDATE, unOld, hSession);
271 #ifdef HDC_SUPPORT_UART
272         if (hSession->connType == CONN_SERIAL and clsUARTServ!= nullptr) {
273             WRITE_LOG(LOG_DEBUG, " HdcDaemon::DaemonSessionHandshake %s",
274                       handshake.ToDebugString().c_str());
275             if (clsUARTServ != nullptr) {
276                 (static_cast<HdcDaemonUART *>(clsUARTServ))->OnNewHandshakeOK(hSession->sessionId);
277             }
278         } else
279 #endif // HDC_SUPPORT_UART
280         if (clsUSBServ != nullptr) {
281             (reinterpret_cast<HdcDaemonUSB *>(clsUSBServ))->OnNewHandshakeOK(hSession->sessionId);
282         }
283 
284         handshake.sessionId = 0;
285         handshake.connectKey = "";
286     }
287     if (enableSecure && !HandDaemonAuth(hSession, channelId, handshake)) {
288         return false;
289     }
290     string version = Base::GetVersion() + HDC_MSG_HASH;
291 
292     WRITE_LOG(LOG_DEBUG, "receive hs version = %s", handshake.version.c_str());
293 
294     if (!handshake.version.empty() && handshake.version != version) {
295         WRITE_LOG(LOG_FATAL, "DaemonSessionHandshake failed! version not match [%s] vs [%s]",
296             handshake.version.c_str(), version.c_str());
297 #ifdef HDC_CHECK_CHECK
298 	hSession->availTailIndex = 0;
299         handshake.banner = HANDSHAKE_FAILED;
300         string failedString = SerialStruct::SerializeToString(handshake);
301         Send(hSession->sessionId, channelId, CMD_KERNEL_HANDSHAKE, (uint8_t *)failedString.c_str(),
302              failedString.size());
303         return false;
304 #endif
305     }
306     if (handshake.version.empty()) {
307         handshake.version = Base::GetVersion();
308         WRITE_LOG(LOG_FATAL, "set version if check mode = %s", handshake.version.c_str());
309     }
310     // handshake auth OK.Can append the sending device information to HOST
311 #ifdef HDC_DEBUG
312     WRITE_LOG(LOG_INFO, "session %u handshakeOK send back CMD_KERNEL_HANDSHAKE", hSession->sessionId);
313 #endif
314     char hostName[BUF_SIZE_MEDIUM] = "";
315     size_t len = sizeof(hostName);
316     uv_os_gethostname(hostName, &len);
317     handshake.authType = AUTH_OK;
318     handshake.buf = hostName;
319     string bufString = SerialStruct::SerializeToString(handshake);
320     Send(hSession->sessionId, channelId, CMD_KERNEL_HANDSHAKE,
321          reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())), bufString.size());
322     hSession->handshakeOK = true;
323     return true;
324 }
325 
IsExpectedParam(const string & param,const string & expect)326 bool HdcDaemon::IsExpectedParam(const string& param, const string& expect)
327 {
328     string out;
329     SystemDepend::GetDevItem(param.c_str(), out);
330     return (out.empty() || out == expect); // default empty
331 }
332 
CheckControl(const uint16_t command)333 bool HdcDaemon::CheckControl(const uint16_t command)
334 {
335     bool ret = false; // default no debug
336     switch (command) { // this switch is match RedirectToTask function
337         case CMD_UNITY_EXECUTE:
338         case CMD_UNITY_REMOUNT:
339         case CMD_UNITY_REBOOT:
340         case CMD_UNITY_RUNMODE:
341         case CMD_UNITY_HILOG:
342         case CMD_UNITY_ROOTRUN:
343         case CMD_UNITY_TERMINATE:
344         case CMD_UNITY_BUGREPORT_INIT:
345         case CMD_JDWP_LIST:
346         case CMD_JDWP_TRACK:
347         case CMD_SHELL_INIT:
348         case CMD_SHELL_DATA: {
349             ret = IsExpectedParam("persist.hdc.control.shell", "true");
350             break;
351         }
352         case CMD_FILE_CHECK:
353         case CMD_FILE_DATA:
354         case CMD_FILE_FINISH:
355         case CMD_FILE_INIT:
356         case CMD_FILE_BEGIN:
357         case CMD_FILE_MODE:
358         case CMD_DIR_MODE:
359         case CMD_APP_CHECK:
360         case CMD_APP_DATA:
361         case CMD_APP_UNINSTALL: {
362             ret = IsExpectedParam("persist.hdc.control.file", "true");
363             break;
364         }
365         case CMD_FORWARD_INIT:
366         case CMD_FORWARD_CHECK:
367         case CMD_FORWARD_ACTIVE_MASTER:
368         case CMD_FORWARD_ACTIVE_SLAVE:
369         case CMD_FORWARD_DATA:
370         case CMD_FORWARD_FREE_CONTEXT:
371         case CMD_FORWARD_CHECK_RESULT: {
372             ret = IsExpectedParam("persist.hdc.control.fport", "true");
373             break;
374         }
375         default:
376             ret = true; // other ECHO_RAW and so on
377     }
378     return ret;
379 }
380 
FetchCommand(HSession hSession,const uint32_t channelId,const uint16_t command,uint8_t * payload,const int payloadSize)381 bool HdcDaemon::FetchCommand(HSession hSession, const uint32_t channelId, const uint16_t command, uint8_t *payload,
382                              const int payloadSize)
383 {
384     StartTraceScope("HdcDaemon::FetchCommand");
385     bool ret = true;
386     if (!hSession->handshakeOK and command != CMD_KERNEL_HANDSHAKE) {
387         WRITE_LOG(LOG_WARN, "session %u wait CMD_KERNEL_HANDSHAKE , but got command %u",
388                   hSession->sessionId, command);
389         ret = false;
390         return ret;
391     }
392     if (command != CMD_UNITY_BUGREPORT_DATA &&
393         command != CMD_SHELL_DATA &&
394         command != CMD_FORWARD_DATA &&
395         command != CMD_FILE_DATA &&
396         command != CMD_APP_DATA) {
397         WRITE_LOG(LOG_DEBUG, "FetchCommand channelId:%u command:%u", channelId, command);
398     }
399     switch (command) {
400         case CMD_KERNEL_HANDSHAKE: {
401             // session handshake step2
402             ret = DaemonSessionHandshake(hSession, channelId, payload, payloadSize);
403             break;
404         }
405         case CMD_KERNEL_CHANNEL_CLOSE: {  // Daemon is only cleaning up the Channel task
406             ClearOwnTasks(hSession, channelId);
407             if (*payload != 0) {
408                 --(*payload);
409                 Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, payload, 1);
410             }
411             ret = true;
412             break;
413         }
414         default:
415             ret = true;
416             if (CheckControl(command)) {
417                 ret = DispatchTaskData(hSession, channelId, command, payload, payloadSize);
418             } else {
419                 LogMsg(hSession->sessionId, channelId, MSG_FAIL, "debugging is not allowed");
420                 uint8_t count = 1;
421                 Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1);
422             }
423             break;
424     }
425     return ret;
426 }
427 
RemoveInstanceTask(const uint8_t op,HTaskInfo hTask)428 bool HdcDaemon::RemoveInstanceTask(const uint8_t op, HTaskInfo hTask)
429 {
430     bool ret = true;
431 
432     if (!hTask->taskClass) {
433         return ret;
434     }
435 
436     switch (hTask->taskType) {
437         case TYPE_UNITY:
438             ret = DoTaskRemove<HdcDaemonUnity>(hTask, op);
439             break;
440         case TYPE_SHELL:
441             ret = DoTaskRemove<HdcShell>(hTask, op);
442             break;
443         case TASK_FILE:
444             ret = DoTaskRemove<HdcTransferBase>(hTask, op);
445             break;
446         case TASK_FORWARD:
447             ret = DoTaskRemove<HdcDaemonForward>(hTask, op);
448             break;
449         case TASK_APP:
450             ret = DoTaskRemove<HdcDaemonApp>(hTask, op);
451             break;
452         default:
453             ret = false;
454             break;
455     }
456     return ret;
457 }
458 
ServerCommand(const uint32_t sessionId,const uint32_t channelId,const uint16_t command,uint8_t * bufPtr,const int size)459 bool HdcDaemon::ServerCommand(const uint32_t sessionId, const uint32_t channelId, const uint16_t command,
460                               uint8_t *bufPtr, const int size)
461 {
462     return Send(sessionId, channelId, command, reinterpret_cast<uint8_t *>(bufPtr), size) > 0;
463 }
464 
JdwpNewFileDescriptor(const uint8_t * buf,const int bytesIO)465 void HdcDaemon::JdwpNewFileDescriptor(const uint8_t *buf, const int bytesIO)
466 {
467     uint8_t spcmd = *const_cast<uint8_t *>(buf);
468     if (spcmd == SP_JDWP_NEWFD) {
469         int cnt = sizeof(uint8_t) + sizeof(uint32_t) * 2;
470         if (bytesIO < cnt) {
471             WRITE_LOG(LOG_FATAL, "jdwp newfd data insufficient bytesIO:%d", bytesIO);
472             return;
473         }
474         uint32_t pid = *reinterpret_cast<uint32_t *>(const_cast<uint8_t *>(buf + 1));
475         uint32_t fd = *reinterpret_cast<uint32_t *>(const_cast<uint8_t *>(buf + 5));  // 5 : fd offset
476         ((HdcJdwp *)clsJdwp)->SendJdwpNewFD(pid, fd);
477     } else if (spcmd == SP_ARK_NEWFD) {
478         // SP_ARK_NEWFD | fd[1] | ark:pid@tid@Debugger
479         int cnt = sizeof(uint8_t) + sizeof(uint32_t);
480         if (bytesIO < cnt) {
481             WRITE_LOG(LOG_FATAL, "ark newfd data insufficient bytesIO:%d", bytesIO);
482             return;
483         }
484         int32_t fd = *reinterpret_cast<int32_t *>(const_cast<uint8_t *>(buf + 1));
485         std::string arkstr = std::string(
486             reinterpret_cast<char *>(const_cast<uint8_t *>(buf + 5)), bytesIO - 5);  // 5 : fd offset
487         WRITE_LOG(LOG_DEBUG, "JdwpNewFileDescriptor arkstr:%s fd:%d", arkstr.c_str(), fd);
488         ((HdcJdwp *)clsJdwp)->SendArkNewFD(arkstr, fd);
489     }
490 }
491 
NotifyInstanceSessionFree(HSession hSession,bool freeOrClear)492 void HdcDaemon::NotifyInstanceSessionFree(HSession hSession, bool freeOrClear)
493 {
494     if (!freeOrClear) {
495         WRITE_LOG(LOG_WARN, "NotifyInstanceSessionFree freeOrClear false");
496         return;  // ignore step 1
497     }
498     if (clsUSBServ != nullptr) {
499         auto clsUsbModule = reinterpret_cast<HdcDaemonUSB *>(clsUSBServ);
500         clsUsbModule->OnSessionFreeFinally(hSession);
501     }
502 }
503 }  // namespace Hdc
504