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 "include/updater/updater.h"
16 #include <cerrno>
17 #include <chrono>
18 #include <cstdio>
19 #include <iomanip>
20 #include <string>
21 #include <sched.h>
22 #include <syscall.h>
23 #include <sys/stat.h>
24 #include <sys/statvfs.h>
25 #include <sys/wait.h>
26 #include <thread>
27 #include <unistd.h>
28 #include <vector>
29 #include <algorithm>
30 #include "fs_manager/mount.h"
31 #include "language/language_ui.h"
32 #include "log/dump.h"
33 #include "log/log.h"
34 #include "package/hash_data_verifier.h"
35 #include "package/pkg_manager.h"
36 #include "package/packages_info.h"
37 #include "parameter.h"
38 #include "misc_info/misc_info.h"
39 #ifdef WITH_SELINUX
40 #include <policycoreutils.h>
41 #include "selinux/selinux.h"
42 #endif // WITH_SELINUX
43 #ifdef UPDATER_USE_PTABLE
44 #include "ptable_parse/ptable_manager.h"
45 #endif
46 #include "updater/hwfault_retry.h"
47 #include "updater/updater_preprocess.h"
48 #include "updater/updater_const.h"
49 #include "updater_main.h"
50 #include "updater_ui_stub.h"
51 #include "utils.h"
52 #include "write_state/write_state.h"
53 
54 namespace Updater {
55 using Updater::Utils::SplitString;
56 using Updater::Utils::Trim;
57 using namespace Hpackage;
58 
59 int g_percentage = 100;
60 int g_tmpProgressValue;
61 int g_tmpValue;
62 
ExtractUpdaterBinary(PkgManager::PkgManagerPtr manager,std::string & packagePath,const std::string & updaterBinary)63 int32_t ExtractUpdaterBinary(PkgManager::PkgManagerPtr manager, std::string &packagePath,
64     const std::string &updaterBinary)
65 {
66     PkgManager::StreamPtr outStream = nullptr;
67     int32_t ret = manager->CreatePkgStream(outStream,  GetWorkPath() + updaterBinary,
68         0, PkgStream::PkgStreamType_Write);
69     if (ret != PKG_SUCCESS) {
70         LOG(ERROR) << "ExtractUpdaterBinary create stream fail";
71         UPDATER_LAST_WORD(UPDATE_CORRUPT);
72         return UPDATE_CORRUPT;
73     }
74     ret = manager->ExtractFile(updaterBinary, outStream);
75     if (ret != PKG_SUCCESS) {
76         LOG(ERROR) << "ExtractUpdaterBinary extract file failed";
77         UPDATER_LAST_WORD(UPDATE_CORRUPT);
78         return UPDATE_CORRUPT;
79     }
80     HashDataVerifier verifier {manager};
81     if (!verifier.LoadHashDataAndPkcs7(packagePath) ||
82         !verifier.VerifyHashData("build_tools/", updaterBinary, outStream)) {
83         LOG(ERROR) << "verify updater_binary failed";
84         UPDATER_LAST_WORD(UPDATE_CORRUPT);
85         return UPDATE_CORRUPT;
86     }
87     manager->ClosePkgStream(outStream);
88     return UPDATE_SUCCESS;
89 }
90 
GetUpdatePackageInfo(PkgManager::PkgManagerPtr pkgManager,const std::string & path)91 int GetUpdatePackageInfo(PkgManager::PkgManagerPtr pkgManager, const std::string &path)
92 {
93     std::vector<std::string> components;
94     if (pkgManager == nullptr) {
95         LOG(ERROR) << "pkgManager is nullptr";
96         return UPDATE_CORRUPT;
97     }
98     int32_t ret = pkgManager->LoadPackage(path, Utils::GetCertName(), components);
99     if (ret != PKG_SUCCESS) {
100         LOG(INFO) << "LoadPackage fail ret :"<< ret;
101         return ret;
102     }
103     return PKG_SUCCESS;
104 }
105 
IsSpaceCapacitySufficient(const UpdaterParams & upParams)106 UpdaterStatus IsSpaceCapacitySufficient(const UpdaterParams &upParams)
107 {
108     UPDATER_INIT_RECORD;
109     std::vector<uint64_t> stashSizeList = GetStashSizeList(upParams);
110     if (stashSizeList.size() == 0) {
111         LOG(ERROR) << "get stash size error";
112         UPDATER_LAST_WORD(UPDATE_ERROR);
113         return UPDATE_ERROR;
114     }
115     uint64_t maxStashSize =  *max_element(stashSizeList.begin(), stashSizeList.end());
116     LOG(INFO) << "get max stash size:" << maxStashSize;
117     uint64_t totalPkgSize = maxStashSize + MIN_UPDATE_SPACE;
118 
119     if (CheckStatvfs(totalPkgSize) != UPDATE_SUCCESS) {
120         LOG(ERROR) << "CheckStatvfs error";
121         UPDATER_LAST_WORD(UPDATE_ERROR);
122         return UPDATE_ERROR;
123     }
124     return UPDATE_SUCCESS;
125 }
126 
GetStashSizeList(const UpdaterParams & upParams)127 std::vector<uint64_t> GetStashSizeList(const UpdaterParams &upParams)
128 {
129     const std::string maxStashFileName = "all_max_stash";
130     std::vector<uint64_t> stashSizeList;
131     for (unsigned int i = upParams.pkgLocation; i < upParams.updatePackage.size(); i++) {
132         PkgManager::PkgManagerPtr pkgManager = Hpackage::PkgManager::CreatePackageInstance();
133         if (pkgManager == nullptr) {
134             LOG(ERROR) << "pkgManager is nullptr";
135             UPDATER_LAST_WORD(UPDATE_CORRUPT);
136             return std::vector<uint64_t> {};
137         }
138 
139         std::vector<std::string> fileIds;
140         int ret = pkgManager->LoadPackageWithoutUnPack(upParams.updatePackage[i], fileIds);
141         if (ret != PKG_SUCCESS) {
142             LOG(ERROR) << "LoadPackageWithoutUnPack failed " << upParams.updatePackage[i];
143             PkgManager::ReleasePackageInstance(pkgManager);
144             UPDATER_LAST_WORD(UPDATE_CORRUPT);
145             return  std::vector<uint64_t> {};
146         }
147 
148         const FileInfo *info = pkgManager->GetFileInfo(maxStashFileName);
149         if (info == nullptr) {
150             LOG(INFO) << "all_max_stash not exist " << upParams.updatePackage[i];
151             stashSizeList.push_back(0);
152             PkgManager::ReleasePackageInstance(pkgManager);
153             continue;
154         }
155 
156         PkgManager::StreamPtr outStream = nullptr;
157         ret = pkgManager->CreatePkgStream(outStream, maxStashFileName, info->unpackedSize,
158             PkgStream::PkgStreamType_MemoryMap);
159         if (outStream == nullptr || ret != PKG_SUCCESS) {
160             LOG(ERROR) << "Create stream fail " << maxStashFileName << " in " << upParams.updatePackage[i];
161             PkgManager::ReleasePackageInstance(pkgManager);
162             UPDATER_LAST_WORD(UPDATE_CORRUPT);
163             return std::vector<uint64_t> {};
164         }
165 
166         ret = pkgManager->ExtractFile(maxStashFileName, outStream);
167         if (ret != PKG_SUCCESS) {
168             LOG(ERROR) << "ExtractFile fail " << maxStashFileName << " in " << upParams.updatePackage[i];
169             PkgManager::ReleasePackageInstance(pkgManager);
170             UPDATER_LAST_WORD(UPDATE_CORRUPT);
171             return std::vector<uint64_t> {};
172         }
173         PkgBuffer data {};
174         outStream->GetBuffer(data);
175         std::string str(reinterpret_cast<char*>(data.buffer), data.length);
176         int64_t maxStashSize = std::stoll(str);
177         stashSizeList.push_back(static_cast<uint64_t>(maxStashSize));
178         PkgManager::ReleasePackageInstance(pkgManager);
179     }
180     return stashSizeList;
181 }
182 
CheckStatvfs(const uint64_t totalPkgSize)183 int CheckStatvfs(const uint64_t totalPkgSize)
184 {
185     struct statvfs64 updaterVfs;
186     if (access("/sdcard/updater", 0) == 0) {
187         if (statvfs64("/sdcard", &updaterVfs) < 0) {
188             LOG(ERROR) << "Statvfs read /sdcard error!";
189             UPDATER_LAST_WORD(UPDATE_ERROR);
190             return UPDATE_ERROR;
191         }
192     } else {
193         if (statvfs64("/data", &updaterVfs) < 0) {
194             LOG(ERROR) << "Statvfs read /data error!";
195             UPDATER_LAST_WORD(UPDATE_ERROR);
196             return UPDATE_ERROR;
197         }
198     }
199     LOG(INFO) << "Number of free blocks = " << updaterVfs.f_bfree << ", Number of free inodes = " << updaterVfs.f_ffree;
200     if (static_cast<uint64_t>(updaterVfs.f_bfree) * static_cast<uint64_t>(updaterVfs.f_bsize) <= totalPkgSize) {
201         LOG(ERROR) << "Can not update, free space is not enough";
202         UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_SPACE_NOTENOUGH), true);
203         UPDATER_UI_INSTANCE.Sleep(UI_SHOW_DURATION);
204         UPDATER_LAST_WORD(UPDATE_ERROR);
205         return UPDATE_ERROR;
206     }
207     return UPDATE_SUCCESS;
208 }
209 
GetTmpProgressValue()210 int GetTmpProgressValue()
211 {
212     return g_tmpProgressValue;
213 }
214 
SetTmpProgressValue(int value)215 void SetTmpProgressValue(int value)
216 {
217     g_tmpProgressValue = value;
218 }
219 
ProgressSmoothHandler(int beginProgress,int endProgress)220 void ProgressSmoothHandler(int beginProgress, int endProgress)
221 {
222     if (endProgress < 0 || endProgress > FULL_PERCENT_PROGRESS || beginProgress < 0) {
223         return;
224     }
225     while (beginProgress < endProgress) {
226         int increase = (endProgress - beginProgress) / PROGRESS_VALUE_CONST;
227         beginProgress += increase;
228         if (beginProgress >= endProgress || increase == 0) {
229             break;
230         } else {
231             UPDATER_UI_INSTANCE.ShowProgress(beginProgress);
232             UPDATER_UI_INSTANCE.Sleep(SHOW_FULL_PROGRESS_TIME);
233         }
234     }
235 }
236 
237 __attribute__((weak)) bool PreStartBinaryEntry([[maybe_unused]] const std::string &path)
238 {
239     LOG(INFO) << "pre binary process";
240     return true;
241 }
242 
DoInstallUpdaterPackage(PkgManager::PkgManagerPtr pkgManager,UpdaterParams & upParams,PackageUpdateMode updateMode)243 UpdaterStatus DoInstallUpdaterPackage(PkgManager::PkgManagerPtr pkgManager, UpdaterParams &upParams,
244     PackageUpdateMode updateMode)
245 {
246     UPDATER_INIT_RECORD;
247     UPDATER_UI_INSTANCE.ShowProgressPage();
248     if (upParams.callbackProgress == nullptr) {
249         LOG(ERROR) << "CallbackProgress is nullptr";
250         UPDATER_LAST_WORD(UPDATE_CORRUPT);
251         return UPDATE_CORRUPT;
252     }
253     upParams.callbackProgress(upParams.initialProgress * FULL_PERCENT_PROGRESS);
254     if (pkgManager == nullptr) {
255         LOG(ERROR) << "pkgManager is nullptr";
256         UPDATER_LAST_WORD(UPDATE_CORRUPT);
257         return UPDATE_CORRUPT;
258     }
259 
260     if (SetupPartitions(updateMode != SDCARD_UPDATE || upParams.sdExtMode == SDCARD_UPDATE_FROM_DEV ||
261         upParams.sdExtMode == SDCARD_UPDATE_FROM_DATA || Utils::CheckUpdateMode(Updater::SDCARD_INTRAL_MODE) ||
262         Utils::CheckUpdateMode(Updater::FACTORY_INTERNAL_MODE)) != 0) {
263         UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_SETPART_FAIL), true);
264         UPDATER_LAST_WORD(UPDATE_ERROR);
265         return UPDATE_ERROR;
266     }
267 
268     if (upParams.retryCount > 0) {
269         LOG(INFO) << "Retry for " << upParams.retryCount << " time(s)";
270     }
271     int ret = GetUpdatePackageInfo(pkgManager, upParams.updatePackage[upParams.pkgLocation]);
272     if (ret != 0) {
273         LOG(ERROR) << "get update package info fail";
274         return UPDATE_CORRUPT;
275     }
276     if (!PreStartBinaryEntry(upParams.updatePackage[upParams.pkgLocation])) {
277         LOG(ERROR) << "pre binary process failed";
278         return UPDATE_ERROR;
279     }
280 
281     g_tmpProgressValue = 0;
282     UpdaterStatus updateRet = StartUpdaterProc(pkgManager, upParams);
283     if (updateRet != UPDATE_SUCCESS) {
284         UPDATER_UI_INSTANCE.ShowUpdInfo(TR(UPD_INSTALL_FAIL));
285         LOG(ERROR) << "Install package failed.";
286     }
287     if (WriteResult(upParams.updatePackage[upParams.pkgLocation],
288         updateRet == UPDATE_SUCCESS ? "verify_success" : "verify_fail") != UPDATE_SUCCESS) {
289         LOG(ERROR) << "write update state fail";
290     }
291     return updateRet;
292 }
293 
294 namespace {
SetProgress(const std::vector<std::string> & output,UpdaterParams & upParams)295 void SetProgress(const std::vector<std::string> &output, UpdaterParams &upParams)
296 {
297     if (upParams.callbackProgress == nullptr) {
298         LOG(ERROR) << "CallbackProgress is nullptr";
299         return;
300     }
301     if (output.size() < DEFAULT_PROCESS_NUM) {
302         LOG(ERROR) << "check output fail";
303         return;
304     }
305     auto outputInfo = Trim(output[1]);
306     float frac = std::stof(output[1]);
307     int tmpProgressValue = 0;
308     if (frac >= -EPSINON && frac <= EPSINON) {
309         return;
310     } else {
311         tmpProgressValue = static_cast<int>(frac * g_percentage);
312     }
313     if (frac >= FULL_EPSINON && g_tmpValue + g_percentage < FULL_PERCENT_PROGRESS) {
314         g_tmpValue += g_percentage;
315         g_tmpProgressValue = g_tmpValue;
316         upParams.callbackProgress(g_tmpProgressValue *
317             upParams.currentPercentage + upParams.initialProgress * FULL_PERCENT_PROGRESS);
318         return;
319     }
320     g_tmpProgressValue = tmpProgressValue + g_tmpValue;
321     if (g_tmpProgressValue == 0) {
322         return;
323     }
324     upParams.callbackProgress(g_tmpProgressValue *
325         upParams.currentPercentage + upParams.initialProgress * FULL_PERCENT_PROGRESS);
326 }
327 }
328 
HandleChildOutput(const std::string & buffer,int32_t bufferLen,bool & retryUpdate,UpdaterParams & upParams)329 void HandleChildOutput(const std::string &buffer, int32_t bufferLen, bool &retryUpdate, UpdaterParams &upParams)
330 {
331     if (bufferLen == 0) {
332         return;
333     }
334     std::string str = buffer;
335     std::vector<std::string> output = SplitString(str, ":");
336     if (output.size() < DEFAULT_PROCESS_NUM) {
337         LOG(ERROR) << "check output fail";
338         return;
339     }
340     auto outputHeader = Trim(output[0]);
341     if (outputHeader == "write_log") {
342         auto outputInfo = Trim(output[1]);
343         LOG(INFO) << outputInfo;
344     } else if (outputHeader == "retry_update") {
345         retryUpdate = true;
346         auto outputInfo = Trim(output[1]);
347         HwFaultRetry::GetInstance().SetFaultInfo(outputInfo);
348     } else if (outputHeader == "ui_log") {
349         auto outputInfo = Trim(output[1]);
350     } else if (outputHeader == "show_progress") {
351         g_tmpValue = g_tmpProgressValue;
352         auto outputInfo = Trim(output[1]);
353         float frac;
354         std::vector<std::string> progress = SplitString(outputInfo, ",");
355         if (progress.size() != DEFAULT_PROCESS_NUM) {
356             LOG(ERROR) << "show progress with wrong arguments";
357         } else {
358             frac = std::stof(progress[0]);
359             g_percentage = static_cast<int>(frac * FULL_PERCENT_PROGRESS);
360         }
361     } else if (outputHeader == "set_progress") {
362         SetProgress(output, upParams);
363     } else {
364         LOG(WARNING) << "Child process returns unexpected message.";
365     }
366 }
367 
ExcuteSubProc(const UpdaterParams & upParams,const std::string & fullPath,int pipeWrite)368 void ExcuteSubProc(const UpdaterParams &upParams, const std::string &fullPath, int pipeWrite)
369 {
370     // Set process scheduler to normal if current scheduler is
371     // SCHED_FIFO, which may cause bad performance.
372     int policy = syscall(SYS_sched_getscheduler, getpid());
373     if (policy == -1) {
374         LOG(INFO) << "Cannnot get current process scheduler";
375     } else if (policy == SCHED_FIFO) {
376         LOG(DEBUG) << "Current process with scheduler SCHED_FIFO";
377         struct sched_param sp = {
378             .sched_priority = 0,
379         };
380         if (syscall(SYS_sched_setscheduler, getpid(), SCHED_OTHER, &sp) < 0) {
381             LOG(WARNING) << "Cannot set current process schedule with SCHED_OTHER";
382         }
383     }
384     const std::string retryPara = upParams.retryCount > 0 ? "retry=1" : "retry=0";
385     execl(fullPath.c_str(), fullPath.c_str(), upParams.updatePackage[upParams.pkgLocation].c_str(),
386             std::to_string(pipeWrite).c_str(), retryPara.c_str(), nullptr);
387     LOG(ERROR) << "Execute updater binary failed";
388     UPDATER_LAST_WORD(UPDATE_ERROR);
389     exit(-1);
390 }
391 
HandlePipeMsg(UpdaterParams & upParams,int pipeRead,bool & retryUpdate)392 UpdaterStatus HandlePipeMsg(UpdaterParams &upParams, int pipeRead, bool &retryUpdate)
393 {
394     char buffer[MAX_BUFFER_SIZE] = {0};
395     FILE* fromChild = fdopen(pipeRead, "r");
396     if (fromChild == nullptr) {
397         LOG(ERROR) << "fdopen pipeRead failed";
398         return UPDATE_ERROR;
399     }
400     while (fgets(buffer, MAX_BUFFER_SIZE - 1, fromChild) != nullptr) {
401         char *pch = strrchr(buffer, '\n');
402         if (pch != nullptr) {
403             *pch = '\0';
404         }
405         if (strstr(buffer, "subProcessResult") != nullptr) {
406             LOG(INFO) << "subProcessResult: " << buffer;
407             break;
408         }
409         HandleChildOutput(buffer, MAX_BUFFER_SIZE, retryUpdate, upParams);
410     }
411     LOG(INFO) << "HandlePipeMsg end";
412     fclose(fromChild);
413     return UPDATE_SUCCESS;
414 }
415 
CheckProcStatus(pid_t pid,bool retryUpdate)416 UpdaterStatus CheckProcStatus(pid_t pid, bool retryUpdate)
417 {
418     int status;
419     if (waitpid(pid, &status, 0) == -1) {
420         LOG(ERROR) << "waitpid error";
421         return UPDATE_ERROR;
422     }
423     if (retryUpdate) {
424         return UPDATE_RETRY;
425     }
426 
427     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
428         if (WIFEXITED(status)) {
429             LOG(ERROR) << "exited, status= " << WEXITSTATUS(status);
430         } else if (WIFSIGNALED(status)) {
431             LOG(ERROR) << "killed by signal " << WTERMSIG(status);
432         } else if (WIFSTOPPED(status)) {
433             LOG(ERROR) << "stopped by signal " << WSTOPSIG(status);
434         }
435         return UPDATE_ERROR;
436     }
437     LOG(DEBUG) << "Updater process finished.";
438     return UPDATE_SUCCESS;
439 }
440 
StartUpdaterProc(PkgManager::PkgManagerPtr pkgManager,UpdaterParams & upParams)441 UpdaterStatus StartUpdaterProc(PkgManager::PkgManagerPtr pkgManager, UpdaterParams &upParams)
442 {
443     UPDATER_INIT_RECORD;
444     int pfd[DEFAULT_PIPE_NUM]; /* communication between parent and child */
445     if (pipe(pfd) < 0) {
446         LOG(ERROR) << "Create pipe failed: ";
447         UPDATER_LAST_WORD(UPDATE_ERROR);
448         return UPDATE_ERROR;
449     }
450     if (pkgManager == nullptr) {
451         LOG(ERROR) << "pkgManager is nullptr";
452         UPDATER_LAST_WORD(UPDATE_CORRUPT);
453         return UPDATE_CORRUPT;
454     }
455 
456     int pipeRead = pfd[0];
457     int pipeWrite = pfd[1];
458     std::string fullPath = GetWorkPath() + std::string(UPDATER_BINARY);
459     (void)Utils::DeleteFile(fullPath);
460 
461     if (ExtractUpdaterBinary(pkgManager, upParams.updatePackage[upParams.pkgLocation], UPDATER_BINARY) != 0) {
462         LOG(INFO) << "There is no valid updater_binary in package, use updater_binary in device";
463         fullPath = "/bin/updater_binary";
464     }
465 
466 #ifdef UPDATER_UT
467     fullPath = "/data/updater/updater_binary";
468 #endif
469 
470     if (chmod(fullPath.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
471         LOG(ERROR) << "Failed to change mode";
472     }
473 
474 #ifdef WITH_SELINUX
475     Restorecon(fullPath.c_str());
476 #endif // WITH_SELINUX
477 
478     pid_t pid = fork();
479     if (pid < 0) {
480         ERROR_CODE(CODE_FORK_FAIL);
481         UPDATER_LAST_WORD(UPDATE_ERROR);
482         return UPDATE_ERROR;
483     }
484 
485     if (pid == 0) { // child
486         #ifdef WITH_SELINUX
487         setcon("u:r:updater_binary:s0");
488         #endif // WITH_SELINUX
489         close(pipeRead);   // close read endpoint
490         ExcuteSubProc(upParams, fullPath, pipeWrite);
491     }
492 
493     close(pipeWrite); // close write endpoint
494     bool retryUpdate = false;
495     if (HandlePipeMsg(upParams, pipeRead, retryUpdate) != UPDATE_SUCCESS) {
496         return UPDATE_ERROR;
497     }
498 
499     return CheckProcStatus(pid, retryUpdate);
500 }
501 
GetWorkPath()502 std::string GetWorkPath()
503 {
504     if (Utils::IsUpdaterMode()) {
505         return G_WORK_PATH;
506     }
507 
508     return std::string(SYS_INSTALLER_PATH) + "/";
509 }
510 } // namespace Updater
511