Implement undo operation of trust anchor 51/158351/26
authorJunghyun Yeon <jungh.yeon@samsung.com>
Tue, 31 Oct 2017 08:01:28 +0000 (17:01 +0900)
committerJunghyun Yeon <jungh.yeon@samsung.com>
Thu, 19 Apr 2018 05:20:06 +0000 (05:20 +0000)
- Trust-anchor registration/unregistration should be revoked
  when installation has failed.
- Old certificates should be rollbacked so make additional steps
  to perform revoke operation after rollback file has done.
- Disable making symlink for preload rw requests.

Change-Id: Id63f0b248a930f77da959bdd84c127843b9fecac
Signed-off-by: Junghyun Yeon <jungh.yeon@samsung.com>
src/common/step/mount/step_mount_unpacked.cc
src/common/step/mount/step_mount_update.cc
src/common/step/security/step_register_trust_anchor.cc
src/common/step/security/step_register_trust_anchor.h
src/common/step/security/step_revoke_trust_anchor.cc [new file with mode: 0644]
src/common/step/security/step_revoke_trust_anchor.h [new file with mode: 0644]
src/common/step/security/step_unregister_trust_anchor.cc
src/common/step/security/step_unregister_trust_anchor.h

index 7e0ff8c3da18dac73922f84230694333139de35a..3bed9e6f8dee2957fd4dad923386dd9e92bb733e 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <string>
 
+#include "common/paths.h"
 #include "common/utils/file_util.h"
 #include "common/tzip_interface.h"
 
@@ -41,6 +42,15 @@ Step::Status StepMountUnpacked::undo() {
   }
 
   RemoveAll(context_->unpacked_dir_path.get());
+
+  if (context_->request_type.get() == RequestType::MountUpdate) {
+    bf::path mount_point = GetMountLocation(context_->GetPkgPath());
+    TzipInterface tzip_final(mount_point);
+    if (!tzip_final.UnmountZip()) {
+      LOG(ERROR) << "Failed to unmount zip package after revoke";
+      return Status::APP_DIR_ERROR;
+    }
+  }
   return Status::OK;
 }
 
index bca5093ba01e86f19084921cdcaf95c783de9086..76452cf4e359eb1a0eba527e45c2d9c84988f14c 100644 (file)
@@ -89,6 +89,14 @@ Step::Status StepMountUpdate::undo() {
                  << backup_zip_location;
       return Status::APP_DIR_ERROR;
     }
+
+    // mount previous file for re-registration of trust anchor
+    bf::path zip_destination_path =
+      GetZipPackageLocation(context_->GetPkgPath(), context_->pkgid.get());
+    if (!tzip_final.MountZip(zip_destination_path)) {
+      LOG(ERROR) << "Failed to mount zip package in installation path";
+      return Status::APP_DIR_ERROR;
+    }
   }
   return Status::OK;
 }
index 7b2f9410a7a083ccb72e314b089162d16477b3b0..74d92cbca1ac396fdede1358e2159813d69f0a65 100644 (file)
@@ -26,8 +26,8 @@ bool RemoveWgtTrustAnchorSymLinks(const bf::path& path) {
   for (bf::directory_iterator file(path);
       file != bf::directory_iterator(); ++file) {
     bf::path current(file->path());
-    if (bf::is_symlink(symlink_status(current)))
-      if (!Remove(current))
+    if (bf::is_symlink(symlink_status(current)) &&
+      !bf::remove(current))
         return false;
   }
   return true;
@@ -42,6 +42,11 @@ StepRegisterTrustAnchor::StepRegisterTrustAnchor(
 }
 
 Step::Status StepRegisterTrustAnchor::precheck() {
+  if (context_->GetPkgPath().empty()) {
+    LOG(ERROR) << "pkg path is empty";
+    return Step::Status::INVALID_VALUE;
+  }
+
   if (!context_->manifest_data.get()) {
     LOG(ERROR) << "manifest_data attribute is empty";
     return Step::Status::INVALID_VALUE;
@@ -53,6 +58,8 @@ Step::Status StepRegisterTrustAnchor::precheck() {
 Step::Status StepRegisterTrustAnchor::process() {
   int ret;
   bf::path pkg_certs_path = context_->GetPkgPath() / kTpkTrustAnchorPath;
+  manifest_x* manifest = context_->manifest_data.get();
+
   if (register_type_ == RegisterType::UPDATE) {
     ret = trust_anchor_uninstall(context_->pkgid.get().c_str(),
         context_->uid.get());
@@ -61,23 +68,27 @@ Step::Status StepRegisterTrustAnchor::process() {
       return Step::Status::SECURITY_ERROR;
     }
 
-    if (!context_->pkg_type.get().compare(kWgt)) {
-      if (!common_installer::CreateDir(pkg_certs_path))
-        return Step::Status::APP_DIR_ERROR;
-      if (!RemoveWgtTrustAnchorSymLinks(pkg_certs_path))
+    if (!context_->partial_rw.get() &&
+        !context_->pkg_type.get().compare(kWgt)) {
+      if (bf::exists(pkg_certs_path) &&
+          !RemoveWgtTrustAnchorSymLinks(pkg_certs_path))
         return Step::Status::APP_DIR_ERROR;
     }
   }
 
-  manifest_x* manifest = context_->manifest_data.get();
   if (!manifest->use_system_certs)
     return Step::Status::OK;
 
-  if (!context_->pkg_type.get().compare(kWgt)) {
-    // For wgt package, create
-    // [pkg_root]/res/.trust-anchor directory and create symbolic link
+  if (!context_->pkg_type.get().compare(kWgt) &&
+      (context_->request_type.get() != RequestType::ManifestPartialInstall &&
+      context_->request_type.get() != RequestType::ManifestPartialUpdate &&
+      context_->request_type.get() != RequestType::PartialUninstall &&
+      context_->request_type.get() != RequestType::ReadonlyUpdateUninstall)) {
+    // For wgt package,
+    // create [pkg_root]/res/.trust-anchor directory and create symbolic link
     if (!common_installer::CreateDir(pkg_certs_path))
       return Step::Status::APP_DIR_ERROR;
+
     bf::path pkg_certs_src_path =
         context_->GetPkgPath() / "res/wgt" / kWgtTrustAnchorPath;
     for (bf::directory_iterator file(pkg_certs_src_path);
@@ -104,5 +115,23 @@ Step::Status StepRegisterTrustAnchor::process() {
   return Step::Status::OK;
 }
 
+Step::Status StepRegisterTrustAnchor::undo() {
+  manifest_x* manifest = context_->manifest_data.get();
+  if (!manifest->use_system_certs)
+    return Step::Status::OK;
+
+  int ret = trust_anchor_uninstall(context_->pkgid.get().c_str(),
+      context_->uid.get());
+  if (ret != TRUST_ANCHOR_ERROR_NONE) {
+    LOG(ERROR) << "Failed to unregister trust anchor. error : " << ret;
+    return Step::Status::SECURITY_ERROR;
+  }
+
+  // Re-registration of trust anchor with previous value
+  // should be performed after rollback files.
+
+  return Step::Status::OK;
+}
+
 }  // namespace security
 }  // namespace common_installer
index 8fb898d97638438dcc448242cf93a6ce866ef115..1f7580694bc528569464a52b7ae35b95cb146e09 100644 (file)
@@ -25,7 +25,7 @@ class StepRegisterTrustAnchor : public Step {
   using Step::Step;
 
   Status process() override;
-  Status undo() override { return Status::OK; }
+  Status undo() override;
   Status clean() override { return Status::OK; }
   Status precheck() override;
 
@@ -34,7 +34,6 @@ class StepRegisterTrustAnchor : public Step {
 
   STEP_NAME(StepRegisterTrustAnchor)
 };
-
 }  // namespace security
 }  // namespace common_installer
 
diff --git a/src/common/step/security/step_revoke_trust_anchor.cc b/src/common/step/security/step_revoke_trust_anchor.cc
new file mode 100644 (file)
index 0000000..d95a7cd
--- /dev/null
@@ -0,0 +1,88 @@
+// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a apache 2.0 license that can be
+// found in the LICENSE file.
+
+#include "common/step/security/step_revoke_trust_anchor.h"
+
+#include <trust-anchor.h>
+#include <boost/filesystem.hpp>
+
+#include <string>
+
+#include "common/utils/file_util.h"
+
+namespace common_installer {
+namespace security {
+
+namespace bf = boost::filesystem;
+
+namespace {
+
+const char kTpkTrustAnchorPath[] = "res/.trust-anchor";
+const char kWgtTrustAnchorPath[] = ".trust-anchor";
+const char kWgt[] = "wgt";
+
+}  // namespace
+
+StepRevokeTrustAnchor::StepRevokeTrustAnchor(InstallerContext* context)
+    : Step(context) {
+}
+
+Step::Status StepRevokeTrustAnchor::undo() {
+  manifest_x* manifest = context_->old_manifest_data.get();
+  if (!manifest) {
+    LOG(ERROR) << "old_manifest_data attribute is empty";
+    return Step::Status::INVALID_VALUE;
+  }
+
+  if (!manifest->use_system_certs)
+    return Step::Status::OK;
+
+  bf::path pkg_certs_path = context_->GetPkgPath() / kTpkTrustAnchorPath;
+  if (!context_->pkg_type.get().compare(kWgt)) {
+    // For wgt package,
+    // create [pkg_root]/res/.trust-anchor directory and create symbolic link
+    if (bf::exists(pkg_certs_path)) {
+      for (bf::directory_iterator file(pkg_certs_path);
+          file != bf::directory_iterator(); ++file) {
+        bf::path current(file->path());
+        if (bf::is_symlink(symlink_status(current))) {
+          if (!bf::remove(current)) {
+            LOG(ERROR) << "Failed to remove previous symlink : " << current;
+            return Step::Status::APP_DIR_ERROR;
+          }
+        }
+      }
+    } else {
+      if (!common_installer::CreateDir(pkg_certs_path))
+        return Step::Status::APP_DIR_ERROR;
+    }
+
+    bf::path pkg_certs_src_path =
+        context_->GetPkgPath() / "res/wgt" / kWgtTrustAnchorPath;
+    for (bf::directory_iterator file(pkg_certs_src_path);
+        file != bf::directory_iterator(); ++file) {
+      bf::path current(file->path());
+      try {
+        bf::create_symlink(current, pkg_certs_path / current.filename());
+      } catch (const bf::filesystem_error& error) {
+        LOG(ERROR) << "Failed to make trust anchor symlink : " << error.what();
+        return Step::Status::APP_DIR_ERROR;
+      }
+    }
+  }
+
+  int ret = trust_anchor_install(context_->pkgid.get().c_str(),
+      context_->uid.get(), pkg_certs_path.string().c_str(),
+      (strcasecmp(manifest->use_system_certs, "true") == 0) ? true : false);
+
+  if (ret != TRUST_ANCHOR_ERROR_NONE) {
+    LOG(ERROR) << "Failed to register trust anchor. error : " << ret;
+    return Step::Status::SECURITY_ERROR;
+  }
+
+  return Step::Status::OK;
+}
+
+}  // namespace security
+}  // namespace common_installer
diff --git a/src/common/step/security/step_revoke_trust_anchor.h b/src/common/step/security/step_revoke_trust_anchor.h
new file mode 100644 (file)
index 0000000..1689468
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a apache 2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef COMMON_STEP_SECURITY_STEP_REVOKE_TRUST_ANCHOR_H_
+#define COMMON_STEP_SECURITY_STEP_REVOKE_TRUST_ANCHOR_H_
+
+#include <manifest_parser/utils/logging.h>
+
+#include "common/step/step.h"
+
+namespace common_installer {
+namespace security {
+
+class StepRevokeTrustAnchor : public Step {
+ public:
+  enum class RegisterType {
+    INSTALL,  // Register trust anchor with new package
+    UPDATE    // Update trust anchor with existing package
+  };
+
+  explicit StepRevokeTrustAnchor(common_installer::InstallerContext* context);
+
+  using Step::Step;
+
+  Status process() override { return Status::OK; }
+  Status undo() override;
+  Status clean() override { return Status::OK; }
+  Status precheck() override { return Status::OK; }
+
+  STEP_NAME(StepRevokeTrustAnchor)
+};
+
+}  // namespace security
+}  // namespace common_installer
+
+#endif  // COMMON_STEP_SECURITY_STEP_REVOKE_TRUST_ANCHOR_H_
index 462e6cbb80d562b81feb0348d633ff88d0e451dc..2f905d9f4b08d8f681475b0191298e2d1b823734 100644 (file)
@@ -13,6 +13,8 @@ namespace security {
 
 namespace bf = boost::filesystem;
 
+const char kTpkTrustAnchorPath[] = "res/.trust-anchor";
+
 Step::Status StepUnregisterTrustAnchor::precheck() {
   if (!context_->manifest_data.get()) {
     LOG(ERROR) << "manifest_data attribute is empty";
@@ -38,5 +40,24 @@ Step::Status StepUnregisterTrustAnchor::process() {
   return Step::Status::OK;
 }
 
+Step::Status StepUnregisterTrustAnchor::undo() {
+  manifest_x* manifest = context_->manifest_data.get();
+
+  if (!manifest->use_system_certs)
+    return Step::Status::OK;
+
+  bf::path pkg_certs_path = context_->GetPkgPath() / kTpkTrustAnchorPath;
+  int ret = trust_anchor_install(context_->pkgid.get().c_str(),
+      context_->uid.get(), pkg_certs_path.string().c_str(),
+      (strcasecmp(manifest->use_system_certs, "true") == 0) ? true : false);
+
+  if (ret != TRUST_ANCHOR_ERROR_NONE) {
+    LOG(ERROR) << "Failed to register trust anchor. error : " << ret;
+    return Step::Status::SECURITY_ERROR;
+  }
+
+  return Step::Status::OK;
+}
+
 }  // namespace security
 }  // namespace common_installer
index cdfba77bdb6a2b2383613b5f7c45ba665451f91e..a7d8b34468662405c403f91250b0316e8ae21b19 100644 (file)
@@ -17,7 +17,7 @@ class StepUnregisterTrustAnchor : public Step {
   using Step::Step;
 
   Status process() override;
-  Status undo() override { return Status::OK; }
+  Status undo() override;
   Status clean() override { return Status::OK; }
   Status precheck() override;