Add recovery mode for ReadonlyUpdateInstall 81/166381/2
authorSangyoon Jang <jeremy.jang@samsung.com>
Fri, 3 Nov 2017 10:11:10 +0000 (19:11 +0900)
committerSangyoon Jang <jeremy.jang@samsung.com>
Wed, 10 Jan 2018 05:10:17 +0000 (14:10 +0900)
Change-Id: I0d672be7831354a5e76d63e67b9220cfd40763ce
Signed-off-by: Sangyoon Jang <jeremy.jang@samsung.com>
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 74177f9..e7c107a 100644 (file)
@@ -30,6 +30,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 = {
@@ -40,6 +41,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) {
@@ -202,6 +205,9 @@ bool RecoveryFile::WriteAndCommitFileContent() {
   case RequestType::MountUpdate:
     fputs(kRecoveryMountUpdateString, handle);
     break;
+  case RequestType::ReadonlyUpdateInstall:
+    fputs(kRecoveryReadonlyUpdateInstallString, handle);
+    break;
   default:
     fputs(kRecoveryUnknownString, handle);
     break;
index 9f333c2..994f9c9 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;
@@ -42,7 +43,6 @@ ci::Step::Status StepParsePreload::process() {
   }
 
   PkgQueryInterface pkg_query(context_->pkgid.get(), context_->uid.get());
-  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 b30500b..c27f101 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 4da4b2b..28977c0 100644 (file)
@@ -91,6 +91,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 603757f..0de7f74 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 80c6fce..6ba6733 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)
@@ -35,9 +36,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 5ad53b2..48e8226 100644 (file)
@@ -51,6 +51,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 56624a8..23e678b 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 df38c6b..e654ae9 100644 (file)
@@ -23,25 +23,31 @@ Step::Status StepOpenRecoveryFile::process() {
   context_->unpacked_dir_path.set(recovery_file->unpacked_dir());
   context_->pkgid.set(recovery_file->pkgid());
   switch (recovery_file->type()) {
-  case RequestType::Install:
-    LOG(INFO) << "Running recovery for new installation";
-    break;
-  case RequestType::Update:
-    LOG(INFO) << "Running recovery for update installation";
-    break;
-  case RequestType::Delta:
-    LOG(INFO) << "Running recovery for delta installation";
-    break;
-  case RequestType::MountInstall:
-    LOG(INFO) << "Running recovery for mount install installation";
-    break;
-  case RequestType::MountUpdate:
-    LOG(INFO) << "Running recovery for mount update installation";
-    break;
-  default:
-    LOG(ERROR) << context_->file_path.get() << " is unknown recovery type ("
-               << static_cast<int>(recovery_file->type()) << ")";
-    return Status::RECOVERY_ERROR;
+    case RequestType::Install:
+      LOG(INFO) << "Running recovery for new installation";
+      break;
+    case RequestType::Update:
+      LOG(INFO) << "Running recovery for update installation";
+      break;
+    case RequestType::Delta:
+      LOG(INFO) << "Running recovery for delta installation";
+      break;
+    case RequestType::MountInstall:
+      LOG(INFO) << "Running recovery for mount install installation";
+      break;
+    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:
+      LOG(ERROR) << context_->file_path.get() << " is unknown recovery type ("
+                 << static_cast<int>(recovery_file->type()) << ")";
+      return Status::RECOVERY_ERROR;
   }
 
   context_->recovery_info.set(RecoveryInfo(std::move(recovery_file)));
index c1d982c..41b1400 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 b4def11..f4653d3 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 1a2ff5f..ceae3b2 100644 (file)
@@ -78,5 +78,25 @@ 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 3e41dd4..1ab29f2 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 deecdb5..b1596d9 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 c05eb2d..e695d04 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;