Add recovery mode for ReadonlyUpdateInstall 74/282774/2
authorSangyoon Jang <jeremy.jang@samsung.com>
Fri, 3 Nov 2017 10:11:10 +0000 (19:11 +0900)
committerIlho Kim <ilho159.kim@samsung.com>
Tue, 11 Oct 2022 09:10:31 +0000 (18:10 +0900)
Change-Id: I0d672be7831354a5e76d63e67b9220cfd40763ce
Signed-off-by: Sangyoon Jang <jeremy.jang@samsung.com>
(cherry picked from commit deaf56fb31def6633e172ef9b83b5303468edaad)

17 files changed:
src/common/recovery_file.cc
src/common/step/configuration/step_parse_preload.cc
src/common/step/filesystem/step_recover_change_owner.h
src/common/step/filesystem/step_recover_files.cc
src/common/step/filesystem/step_recover_files.h
src/common/step/filesystem/step_recover_globalapp_symlinks.cc [new file with mode: 0644]
src/common/step/filesystem/step_recover_globalapp_symlinks.h [new file with mode: 0644]
src/common/step/filesystem/step_remove_globalapp_symlinks.cc
src/common/step/pkgmgr/step_recover_application.cc
src/common/step/pkgmgr/step_recover_application.h
src/common/step/recovery/step_open_recovery_file.cc
src/common/step/recovery/step_recovery.cc
src/common/step/recovery/step_recovery.h
src/common/step/security/step_recover_security.cc
src/common/step/security/step_recover_security.h
src/common/step/security/step_recover_signature.cc
src/common/step/security/step_recover_signature.h

index 113a5335b7f33a564b4799d4a2aa5f6c969192bc..f5d4ba513dc72f4c4d183bd3aaab193363e1513b 100644 (file)
@@ -29,6 +29,7 @@ const char kRecoveryRdsString[] = "RDS";
 const char kRecoveryDeltaString[] = "DELTA";
 const char kRecoveryMountInstallString[] = "MOUNTINSTALL";
 const char kRecoveryMountUpdateString[] = "MOUNTUPDATE";
+const char kRecoveryReadonlyUpdateInstallString[] = "READONLYUPDATEINSTALL";
 const char kRecoveryUnknownString[] = "UNKNOWN";
 
 const std::map<std::string, ci::RequestType> kStringToRequestMap = {
@@ -39,6 +40,8 @@ const std::map<std::string, ci::RequestType> kStringToRequestMap = {
   {kRecoveryDeltaString, ci::RequestType::Delta},
   {kRecoveryMountInstallString, ci::RequestType::MountInstall},
   {kRecoveryMountUpdateString, ci::RequestType::MountUpdate},
+  {kRecoveryReadonlyUpdateInstallString,
+      ci::RequestType::ReadonlyUpdateInstall},
 };
 
 std::string TruncateNewLine(const char* data) {
@@ -204,6 +207,9 @@ bool RecoveryFile::WriteAndCommitFileContent() {
   case RequestType::MountUpdate:
     fputs(kRecoveryMountUpdateString, handle);
     break;
+  case RequestType::ReadonlyUpdateInstall:
+    fputs(kRecoveryReadonlyUpdateInstallString, handle);
+    break;
   default:
     fputs(kRecoveryUnknownString, handle);
     break;
index 2c0bd52cdfb5127ebbcd7a03bff2607c7cf0bf22..62a3323dd05495dcd16b68f3a8c3ed960164222f 100644 (file)
@@ -24,6 +24,7 @@ namespace common_installer {
 namespace configuration {
 
 ci::Step::Status StepParsePreload::process() {
+  RequestType req_type = context_->request_type.get();
   const char* readonly_val = context_->manifest_data.get()->readonly;
   if (!readonly_val || (readonly_val && strlen(readonly_val) == 0)) {
     if (readonly_val)
@@ -31,7 +32,7 @@ ci::Step::Status StepParsePreload::process() {
     if (context_->is_readonly_package.get()) {
       context_->manifest_data.get()->readonly = strdup("true");
 
-      if (getuid() != 0) {
+      if (getuid() != 0 && req_type != RequestType::Recovery) {
         LOG(ERROR) << "You're not authorized to install readonly app: "
             << context_->pkgid.get().c_str();
         return Status::OPERATION_NOT_ALLOWED;
@@ -41,7 +42,6 @@ ci::Step::Status StepParsePreload::process() {
     }
   }
 
-  RequestType req_type = context_->request_type.get();
   const char* preload_val = context_->manifest_data.get()->preload;
   if (!preload_val || (preload_val && strlen(preload_val) == 0)) {
     if (preload_val)
index b30500b5dfe274f0d46b6892d5888af422e4b40c..c27f10169853d8081ed4cef6072eab0c8dca08bc 100644 (file)
@@ -27,6 +27,7 @@ class StepRecoverChangeOwner : public recovery::StepRecovery {
   Status RecoveryNew() override { return Status::OK; };
   Status RecoveryUpdate() override;
   Status RecoveryMountUpdate() override;
+  Status RecoveryReadonlyUpdateInstall() override { return Status::OK; };
 
  private:
   Step::Status ChangeOwnershipIconsAndManifest(const boost::optional<gid_t> gid,
index 0ac09b4b43ddd101d60f4e65b0dc04e6d706de41..63bc7896409365942ae377e5654a4193efa9faf5 100644 (file)
@@ -101,6 +101,18 @@ Step::Status StepRecoverFiles::RecoveryMountUpdate() {
   return Status::OK;
 }
 
+Step::Status StepRecoverFiles::RecoveryReadonlyUpdateInstall() {
+  // Remove package directory at RW area
+  bf::path pkg_path =
+      bf::path(GetRootAppPath(false, context_->uid.get())) /
+      context_->pkgid.get();
+  if (!RemoveAll(pkg_path))
+    return Status::RECOVERY_ERROR;
+
+  LOG(INFO) << "Package files recovery done";
+  return Status::OK;
+}
+
 bool StepRecoverFiles::SetPackagePath() {
   if (context_->pkgid.get().empty())
     return false;
index 4a27a743d6613916ee461c4a4866cefa3679163c..006454bb7045ab1b3c849198307353ea4c63843e 100644 (file)
@@ -29,6 +29,7 @@ class StepRecoverFiles : public recovery::StepRecovery {
   Status RecoveryUpdate() override;
   Status RecoveryMountNew() override;
   Status RecoveryMountUpdate() override;
+  Status RecoveryReadonlyUpdateInstall() override;
 
  private:
   bool SetPackagePath();
diff --git a/src/common/step/filesystem/step_recover_globalapp_symlinks.cc b/src/common/step/filesystem/step_recover_globalapp_symlinks.cc
new file mode 100644 (file)
index 0000000..83cfb11
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#include "common/step/filesystem/step_recover_globalapp_symlinks.h"
+#include "common/step/filesystem/step_remove_globalapp_symlinks.h"
+
+namespace bf = boost::filesystem;
+
+namespace common_installer {
+namespace filesystem {
+
+Step::Status StepRecoverGlobalAppSymlinks::RecoveryReadonlyUpdateInstall() {
+  StepRemoveGlobalAppSymlinks step(context_);
+  Status status = step.precheck();
+  if (status != Status::OK)
+      return status;
+  return step.process();
+}
+
+}  // namespace filesystem
+}  // namespace common_installer
diff --git a/src/common/step/filesystem/step_recover_globalapp_symlinks.h b/src/common/step/filesystem/step_recover_globalapp_symlinks.h
new file mode 100644 (file)
index 0000000..45e6123
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef COMMON_STEP_FILESYSTEM_STEP_RECOVER_GLOBALAPP_SYMLINKS_H_
+#define COMMON_STEP_FILESYSTEM_STEP_RECOVER_GLOBALAPP_SYMLINKS_H_
+
+#include <manifest_parser/utils/logging.h>
+
+#include "common/installer_context.h"
+#include "common/step/recovery/step_recovery.h"
+
+namespace common_installer {
+namespace filesystem {
+
+/**
+ * @brief Recovers symlink files of globalapp
+ *
+ * This is the part of Recovery Mode that is responsible for removing
+ * symlink files for read-only files of globalapp for backward compatibility.
+ */
+class StepRecoverGlobalAppSymlinks : public recovery::StepRecovery {
+ public:
+  using StepRecovery::StepRecovery;
+
+  Status RecoveryNew() override { return Status::OK; }
+  Status RecoveryUpdate() override { return Status::OK; }
+  Status RecoveryReadonlyUpdateInstall() override;
+
+  STEP_NAME(RecoverGlobalAppSymlinks)
+};
+
+}  // namespace filesystem
+}  // namespace common_installer
+
+#endif  // COMMON_STEP_FILESYSTEM_STEP_RECOVER_GLOBALAPP_SYMLINKS_H_
index dae5712b50e793903b3a318053a07cb042d93cce..4b28ac5a10930d8d83ba9aef23593a65c9dc38ec 100644 (file)
@@ -23,7 +23,8 @@ namespace common_installer {
 namespace filesystem {
 
 Step::Status StepRemoveGlobalAppSymlinks::process() {
-  if (context_->is_readonly_package.get())
+  RequestType req_type = context_->request_type.get();
+  if (context_->is_readonly_package.get() && req_type != RequestType::Recovery)
     return Step::Status::OK;
 
   if (context_->request_mode.get() != RequestMode::GLOBAL)
@@ -34,9 +35,9 @@ Step::Status StepRemoveGlobalAppSymlinks::process() {
 
   std::string package_id = context_->pkgid.get();
 
-  RequestType req_type = context_->request_type.get();
   if (req_type == RequestType::Uninstall ||
-      req_type == RequestType::ReadonlyUpdateUninstall) {
+      req_type == RequestType::ReadonlyUpdateUninstall ||
+      req_type == RequestType::Recovery) {
     LOG(INFO) << "Deleting globalapp symlinks for all user, package: "
               << package_id;
     if (!DeleteGlobalAppSymlinksForAllUsers(package_id)) {
index 6640069ed08dd665beeb4825889f45fb419b50cd..a674937eae5d6b79026dd98360f308ae0b3cdb6b 100644 (file)
@@ -44,6 +44,20 @@ Step::Status StepRecoverApplication::RecoveryUpdate() {
   return Status::OK;
 }
 
+Step::Status StepRecoverApplication::RecoveryReadonlyUpdateInstall() {
+  // Hmm... this is just-work solution...
+  manifest_x* manifest_data = context_->manifest_data.get();
+  free(manifest_data->system);
+  manifest_data->system = strdup("true");
+  free(manifest_data->preload);
+  manifest_data->preload = strdup("true");
+  free(manifest_data->readonly);
+  manifest_data->readonly = strdup("true");
+  free(manifest_data->removable);
+  manifest_data->removable = strdup("false");
+  return RecoveryUpdate();
+}
+
 bool StepRecoverApplication::SetXmlPaths() {
   if (context_->pkgid.get().empty())
     return false;
index 56624a8733875e93214d5a770cd070c0d7805814..23e678bd86468197c7208f17676899efff9dae09 100644 (file)
@@ -25,6 +25,8 @@ class StepRecoverApplication : public recovery::StepRecovery {
   using StepRecovery::StepRecovery;
   Status RecoveryNew() override;
   Status RecoveryUpdate() override;
+  Status RecoveryReadonlyUpdateInstall() override;
+
  private:
   bool SetXmlPaths();
 
index 49aeea1992593c402fcff1fde6dfb664ce373272..347991e06f0992f8ea16909c9789f313e515286f 100644 (file)
@@ -38,6 +38,12 @@ Step::Status StepOpenRecoveryFile::process() {
   case RequestType::MountUpdate:
     LOG(INFO) << "Running recovery for mount update installation";
     break;
+  case RequestType::ReadonlyUpdateInstall:
+    LOG(INFO) << "Running recovery for readonly update installation";
+    context_->is_readonly_package.set(true);
+    context_->root_application_path.set(
+        GetRootAppPath(true, context_->uid.get()));
+    break;
   default:
     assert(false && "Not reached");
   }
index c1d982c4c8bc0747532cd7c0f4dc9cd882e2de5f..41b14005a15b6054d90734f08d206ead3e3bce85 100644 (file)
@@ -23,6 +23,8 @@ Step::Status StepRecovery::process() {
     return RecoveryMountNew();
   case RequestType::MountUpdate:
     return RecoveryMountUpdate();
+  case RequestType::ReadonlyUpdateInstall:
+    return RecoveryReadonlyUpdateInstall();
   default:
     LOG(ERROR) << "Recovery is not supported for given type of installation";
     return Status::RECOVERY_ERROR;
@@ -41,5 +43,9 @@ Step::Status StepRecovery::RecoveryMountUpdate() {
   return RecoveryUpdate();
 }
 
+Step::Status StepRecovery::RecoveryReadonlyUpdateInstall() {
+  return RecoveryUpdate();
+}
+
 }  // namespace recovery
 }  // namespace common_installer
index b4def119683ab2c634c5ac4cbfe780baa398b603..f4653d3f0096d2bd87668fc027dfb801bde4d30d 100644 (file)
@@ -37,6 +37,7 @@ class StepRecovery : public Step {
   virtual Status RecoveryDelta();
   virtual Status RecoveryMountNew();
   virtual Status RecoveryMountUpdate();
+  virtual Status RecoveryReadonlyUpdateInstall();
 };
 
 }  // namespace recovery
index 91e4a0d10b1a7a811389d18b001e144ea30933e6..2fb4070e784df4b2e936a4f092291dee48faac65 100644 (file)
@@ -69,5 +69,26 @@ Step::Status StepRecoverSecurity::RecoveryUpdate() {
   }
   return Status::OK;
 }
+
+Step::Status StepRecoverSecurity::RecoveryReadonlyUpdateInstall() {
+  if (!Check(false)) {
+    LOG(ERROR) << "Invalid parameters";
+    return Status::INVALID_VALUE;
+  }
+  std::string error_message;
+  if (!RegisterSecurityContextForManifest(
+      context_->pkgid.get(), context_->pkg_path.get(), context_->uid.get(),
+      &context_->certificate_info.get(), context_->manifest_data.get(),
+      context_->cross_app_rules.get(), &error_message)) {
+    LOG(ERROR) << "Unsuccessful update";
+    if (!error_message.empty()) {
+      LOG(ERROR) << "error_message: " << error_message;
+      on_error(Status::RECOVERY_ERROR, error_message);
+    }
+    return Status::RECOVERY_ERROR;
+  }
+  return Status::OK;
+}
+
 }  // namespace security
 }  // namespace common_installer
index 3e41dd481e5e3a9e48906a4fa0898a5a474b8efb..1ab29f2ca1665daae47b5057639c53ab3442571f 100644 (file)
@@ -29,6 +29,7 @@ class StepRecoverSecurity : public recovery::StepRecovery {
 
   Status RecoveryNew() override;
   Status RecoveryUpdate() override;
+  Status RecoveryReadonlyUpdateInstall() override;
  private:
   bool Check(bool is_update);
 
index deecdb5eb872770b1bde0f5da32b57227f9d3248..b1596d905af3f824a6f1caa6eb6f5e6072f8f457 100644 (file)
@@ -4,10 +4,14 @@
 
 #include "common/step/security/step_recover_signature.h"
 
+#include <boost/filesystem/path.hpp>
+
 #include <string>
 
 #include "common/certificate_validation.h"
 
+namespace bf = boost::filesystem;
+
 namespace common_installer {
 namespace security {
 
@@ -23,5 +27,20 @@ Step::Status StepRecoverSignature::RecoveryUpdate() {
   return Status::OK;
 }
 
+Step::Status StepRecoverSignature::RecoveryReadonlyUpdateInstall() {
+  std::string error_message;
+  PrivilegeLevel level;
+  bf::path signature_root =
+      bf::path(GetRootAppPath(context_->is_readonly_package.get(),
+          context_->uid.get())) / context_->pkgid.get();
+  if (!ValidateSignatures(signature_root, &level,
+                         &context_->certificate_info.get(), false,
+                         &error_message)) {
+    LOG(ERROR) << "Failed to verify signature: " << error_message;
+    return Status::CERT_ERROR;
+  }
+  return Status::OK;
+}
+
 }  // namespace security
 }  // namespace common_installer
index c05eb2dc64a6a7f443fd2aae847d1d964277d338..e695d04526db3c818157c2d335f82cc028b1672f 100644 (file)
@@ -30,6 +30,7 @@ class StepRecoverSignature : public recovery::StepRecovery {
 
   Status RecoveryNew() override { return Status::OK; }
   Status RecoveryUpdate() override;
+  Status RecoveryReadonlyUpdateInstall() override;
 
  private:
   virtual boost::filesystem::path GetSignatureRoot() = 0;