Fix the access issue to shared/res of web app 72/138972/12
authorjongmyeongko <jongmyeong.ko@samsung.com>
Fri, 14 Jul 2017 12:06:58 +0000 (21:06 +0900)
committerjongmyeong ko <jongmyeong.ko@samsung.com>
Tue, 8 Aug 2017 10:34:09 +0000 (10:34 +0000)
Other applications can't access the contents of ${pkg_path}/res/wgt/shared/res
because of SMACK denial.
So, the all contents of ${pkg_path}/res/wgt/shared/res should be in shared/res
to avoid SMACK error.

Also, we should consider delta update issue.
The issue is the signature validation check failure because of unsigned file.
In ${pkg_path}/shared/res, there can be generated files such as apps icon.
and there can be other application's data of shared/res in case of Hybrid package.
These files are unsigend one.
To fix the issue,
unlink and move back all original contents for ${pkg_path}/res/wgt/shared/res
before delta update.

Submit with :
https://review.tizen.org/gerrit/#/c/139133/

Change-Id: I83718f109fbe4614c41977f4d680e65f007dad86
Signed-off-by: jongmyeongko <jongmyeong.ko@samsung.com>
(cherry picked from commit 1e4547168e14eb59fc18c6f586d9a67126587b04)

src/unit_tests/smoke_test.cc
src/wgt/step/filesystem/step_wgt_patch_storage_directories.cc
src/wgt/step/filesystem/step_wgt_undo_patch_storage_directories.cc
src/wgt/step/filesystem/step_wgt_undo_patch_storage_directories.h

index c3dad251a467d87c6ec8b8d0abb70bbfa8a43e63..1fc7165f0eabf5dc3904a3ea8cdd64fd4c27a9e3 100644 (file)
@@ -651,8 +651,8 @@ TEST_F(SmokeTest, SharedRes30) {
   ASSERT_EQ(Install(path, PackageType::WGT), ci::AppInstaller::Result::OK);
   ASSERT_TRUE(ValidatePackage(pkgid, {appid}));
   bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
-  ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT"));  // NOLINT
-  ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "shared" / "res" / "SHARED-WGT"));  // NOLINT
+  ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT"));  // NOLINT
+  ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "shared" / "res" / "SHARED-WGT"));  // NOLINT
 }
 
 TEST_F(SmokeTest, SharedRes30Delta) {
@@ -665,8 +665,8 @@ TEST_F(SmokeTest, SharedRes30Delta) {
   ASSERT_TRUE(ValidatePackage(pkgid, {appid}));
   // Check delta modifications
   bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
-  ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-2"));  // NOLINT
-  ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "shared" / "res" / "SHARED-WGT-2"));  // NOLINT
+  ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-2"));  // NOLINT
+  ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "shared" / "res" / "SHARED-WGT-2"));  // NOLINT
   ASSERT_FALSE(bf::exists(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-1"));  // NOLINT
   ASSERT_FALSE(bf::exists(root_path / pkgid / "shared" / "res" / "SHARED-WGT-1"));  // NOLINT
 }
@@ -679,10 +679,9 @@ TEST_F(SmokeTest, SharedRes30Hybrid) {
   ASSERT_EQ(Install(path, PackageType::HYBRID), ci::AppInstaller::Result::OK);
   ASSERT_TRUE(ValidatePackage(pkgid, {appid1, appid2}));
   bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
-  ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT"));  // NOLINT
-  ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "shared" / "res" / "SHARED-WGT"));  // NOLINT
+  ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT"));  // NOLINT
+  ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "shared" / "res" / "SHARED-WGT"));  // NOLINT
   ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "shared" / "res" / "SHARED-TPK"));  // NOLINT
-  ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-TPK"));  // NOLINT
 }
 
 TEST_F(SmokeTest, SharedRes30HybridDelta) {
@@ -697,10 +696,9 @@ TEST_F(SmokeTest, SharedRes30HybridDelta) {
   ASSERT_TRUE(ValidatePackage(pkgid, {appid1, appid2}));
   // Check delta modifications
   bf::path root_path = ci::GetRootAppPath(false, kTestUserId);
-  ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-2"));  // NOLINT
-  ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "shared" / "res" / "SHARED-WGT-2"));  // NOLINT
+  ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-2"));  // NOLINT
+  ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "shared" / "res" / "SHARED-WGT-2"));  // NOLINT
   ASSERT_TRUE(bf::is_regular_file(root_path / pkgid / "shared" / "res" / "SHARED-TPK-2"));  // NOLINT
-  ASSERT_TRUE(bf::is_symlink(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-TPK-2"));  // NOLINT
   ASSERT_FALSE(bf::exists(root_path / pkgid / "res" / "wgt" / "shared" / "res" / "SHARED-WGT-1"));  // NOLINT
   ASSERT_FALSE(bf::exists(root_path / pkgid / "shared" / "res" / "SHARED-WGT-1"));  // NOLINT
 }
index cb8a2215f93958ac291bb749529e7103867d70d1..dae2b53a0ca9bae25dc3ac81ad8c71160e601afc 100644 (file)
@@ -12,6 +12,7 @@
 
 namespace bf = boost::filesystem;
 namespace bs = boost::system;
+namespace ci = common_installer;
 
 namespace {
 
@@ -31,7 +32,8 @@ common_installer::Step::Status StepWgtPatchStorageDirectories::process() {
 
   int version = std::stoi(context_->manifest_data.get()->api_version);
   if (version >= 3) {
-    LOG(DEBUG) << "Symlinking widget's shared/res directory content in "
+    LOG(DEBUG) <<
+        "Moving and linking widget's shared/res directory content in "
         << context_->pkg_path.get();
     if (!ShareDirFor3x())
       return Status::APP_DIR_ERROR;
@@ -65,43 +67,27 @@ bool StepWgtPatchStorageDirectories::ShareDirFor3x() {
       return false;
     }
   }
-  // link all ${pkg_path}/res/wgt/shared/res content to ${pkg_path}/shared/res
+
+  // move and link all contents of ${pkg_path}res/wgt/shared/res
+  // to ${pkg_path}shared/res
   bf::directory_iterator end_itr;
   for (bf::directory_iterator itr(wgt_shared_res_dir); itr != end_itr; ++itr) {
-    bf::path link_target = itr->path();
-    if (bf::is_symlink(link_target)) {
-      continue;
-    }
-    bf::path link_file = shared_res_dir / link_target.filename();
-    if (bf::exists(link_file)) {
-      LOG(DEBUG) << "shared/res linking: skipping existing " << link_file;
-      continue;
-    }
-    LOG(DEBUG) << "shared/res linking: creating link " << link_file;
-    bs::error_code error;
-    bf::create_symlink(link_target, link_file, error);
-    if (error) {
-      LOG(ERROR) << "shared/res linking: linking failed for " << link_file
-                 << ": " << boost::system::system_error(error).what();
-      return false;
-    }
-  }
-  // link all ${pkg_path}/shared/res content to ${pkg_path}/res/wgt/shared/res
-  for (bf::directory_iterator itr(shared_res_dir); itr != end_itr; ++itr) {
-    bf::path link_target = itr->path();
-    if (bf::is_symlink(link_target)) {
+    bf::path current = itr->path();
+    if (bf::is_symlink(current)) {
       continue;
     }
-    bf::path link_file = wgt_shared_res_dir / link_target.filename();
-    if (bf::exists(link_file)) {
-      LOG(DEBUG) << "shared/res linking: skipping existing " << link_file;
-      continue;
+    bf::path dest = shared_res_dir / current.filename();
+    if (bf::is_directory(current)) {
+      if (!ci::MoveDir(current, dest, ci::FS_MERGE_OVERWRITE))
+        return false;
+    } else {
+      if (!ci::MoveFile(current, dest, true))
+        return false;
     }
-    LOG(DEBUG) << "shared/res linking: creating link " << link_file;
     bs::error_code error;
-    bf::create_symlink(link_target, link_file, error);
+    bf::create_symlink(dest, current, error);
     if (error) {
-      LOG(ERROR) << "shared/res linking: linking failed for " << link_file
+      LOG(ERROR) << "linking failed for " << dest
                  << ": " << boost::system::system_error(error).what();
       return false;
     }
index 241b2ca6d073d76a704bf7e1073ae512e3562894..4909a6a3580ec464e843464ed39046832c0880c2 100644 (file)
@@ -12,6 +12,7 @@
 
 namespace bf = boost::filesystem;
 namespace bs = boost::system;
+namespace ci = common_installer;
 
 namespace {
 
@@ -24,10 +25,11 @@ const char kResWgtSubPath[] = "res/wgt";
 namespace wgt {
 namespace filesystem {
 
-common_installer::Step::Status StepWgtUndoPatchStorageDirectories::process() {
+ci::Step::Status StepWgtUndoPatchStorageDirectories::process() {
   int version = std::stoi(context_->manifest_data.get()->api_version);
   if (version >= 3) {
-    LOG(DEBUG) << "Unlinking widget's shared/res directory content in "
+    LOG(DEBUG) <<
+        "Unlinking and moving widget's shared/res directory content back in "
         << context_->pkg_path.get();
     if (!UndoShareDirFor3x())
       return Status::APP_DIR_ERROR;
@@ -36,57 +38,101 @@ common_installer::Step::Status StepWgtUndoPatchStorageDirectories::process() {
   return Status::OK;
 }
 
+ci::Step::Status StepWgtUndoPatchStorageDirectories::clean() {
+  if (!backup_dir_.empty())
+    ci::RemoveAll(backup_dir_);
+  return Status::OK;
+}
+
+ci::Step::Status StepWgtUndoPatchStorageDirectories::undo() {
+  if (!backup_dir_.empty()) {
+    LOG(DEBUG) << "Restore res/wgt/shared/res from backup dir";
+    // restore link
+    bf::path wgt_shared_res_dir =
+        context_->pkg_path.get() / kResWgtSubPath / kSharedResLocation;
+    bf::path backup_wgt_shared_res = backup_dir_ / "wgt_shared_res";
+    if (!backup_wgt_shared_res.empty()) {
+      if (!ci::RemoveAll(wgt_shared_res_dir)) {
+        LOG(ERROR) << "Failed to remove res/wgt/shared/res";
+        return Status::APP_DIR_ERROR;
+      }
+      if (!ci::CopyDir(backup_dir_, wgt_shared_res_dir,
+                       ci::FS_MERGE_OVERWRITE, false)) {
+        LOG(ERROR) << "Failed to copy from backup";
+        return Status::APP_DIR_ERROR;
+      }
+    }
+    // restore original contents
+    bf::path shared_res_dir = context_->pkg_path.get() / kSharedResLocation;
+    bf::path backup_shared_res = backup_dir_ / "shared_res";
+    if (!backup_shared_res.empty()) {
+      if (!ci::CopyDir(backup_dir_, shared_res_dir,
+                       ci::FS_MERGE_OVERWRITE, false)) {
+        LOG(ERROR) << "Failed to copy from backup";
+        return Status::APP_DIR_ERROR;
+      }
+    }
+  }
+  return Status::OK;
+}
+
 bool StepWgtUndoPatchStorageDirectories::UndoShareDirFor3x() {
   // check if ${pkg_path}/shared/res exists
   bf::path shared_res_dir = context_->pkg_path.get() / kSharedResLocation;
+  if (!bf::exists(shared_res_dir))
+    return true;
   bf::path wgt_shared_res_dir =
       context_->pkg_path.get() / kResWgtSubPath / kSharedResLocation;
-  if (!bf::exists(shared_res_dir))
+  if (!bf::exists(wgt_shared_res_dir))
     return true;
-  // delete symlinks in ${pkg_path}/shared/res
-  if (bf::exists(shared_res_dir)) {
-    bf::directory_iterator end_itr;
-    for (bf::directory_iterator itr(shared_res_dir); itr != end_itr; ++itr) {
-      bf::path link_file = itr->path();
-      if (!bf::is_symlink(link_file)) {
-        continue;
-      }
-      bf::path link_target = bf::read_symlink(link_file);
-      if (link_target.native().substr(0, wgt_shared_res_dir.native().length()) !=
-          wgt_shared_res_dir.native()) {
-        continue;
-      }
-      LOG(DEBUG) << "shared/res linking: removing symlink " << link_file;
-      bs::error_code error;
-      bf::remove(link_file, error);
-      if (error) {
-        LOG(ERROR) << "Failed to remove symlink " << link_file;
-        return false;
-      }
-    }
+
+  if (bf::is_symlink(wgt_shared_res_dir)) {
+    LOG(ERROR) << "Can't support this step, pkg should be fully updated";
+    return false;
   }
-  // delete symlinks in ${pkg_path}/res/wgt/shared/res
-  if (bf::exists(wgt_shared_res_dir)) {
-    bf::directory_iterator end_itr;
-    for (bf::directory_iterator itr(wgt_shared_res_dir); itr != end_itr; ++itr) {
-      bf::path link_file = itr->path();
-      if (!bf::is_symlink(link_file)) {
-        continue;
-      }
-      bf::path link_target = bf::read_symlink(link_file);
-      if (link_target.native().substr(0, shared_res_dir.native().length()) !=
-          shared_res_dir.native()) {
-        continue;
-      }
-      LOG(DEBUG) << "shared/res linking: removing symlink " << link_file;
-      bs::error_code error;
-      bf::remove(link_file, error);
-      if (error) {
-        LOG(ERROR) << "Failed to remove symlink " << link_file;
+
+  // backup for undo
+  backup_dir_ = context_->unpacked_dir_path.get();
+  backup_dir_ += ".SharedRes";
+  bf::path backup_shared_res = backup_dir_ / "shared_res";
+  if (!ci::CreateDir(backup_shared_res))
+    return false;
+  bf::path backup_wgt_shared_res = backup_dir_ / "wgt_shared_res";
+  if (!ci::CopyDir(wgt_shared_res_dir, backup_wgt_shared_res,
+                   ci::FS_MERGE_OVERWRITE, false)) {
+    backup_dir_.clear();
+    return false;
+  }
+
+  // unlink and move all linked contents from ${pkg_path}/shared/res
+  // to ${pkg_path}/res/wgt/shared/res
+  bf::directory_iterator end_itr;
+  for (bf::directory_iterator itr(wgt_shared_res_dir); itr != end_itr; ++itr) {
+    bf::path link_file = itr->path();
+    if (!bf::is_symlink(link_file)) {
+      continue;
+    }
+    bf::path link_target = bf::read_symlink(link_file);
+    if (link_target.native().substr(0, shared_res_dir.native().length()) !=
+        shared_res_dir.native()) {
+      continue;
+    }
+    if (!ci::Remove(link_file))
+      return false;
+    bf::path tmp_backup = backup_shared_res / link_target.filename();
+    if (bf::is_directory(link_target)) {
+      if (!ci::CopyDir(link_target, tmp_backup, ci::FS_MERGE_OVERWRITE, false))
+        return false;
+      if (!ci::MoveDir(link_target, link_file, ci::FS_MERGE_OVERWRITE))
+        return false;
+    } else {
+      if (!ci::CopyFile(link_target, tmp_backup))
+        return false;
+      if (!ci::MoveFile(link_target, link_file, true))
         return false;
-      }
     }
   }
+
   return true;
 }
 
index 382ab728164d5e7e0da89ad0d3aa500fd341cbae..e8494adca7e2cb9c1360a48f9cb3135edc59d14a 100644 (file)
@@ -23,12 +23,13 @@ class StepWgtUndoPatchStorageDirectories :
   using Step::Step;
 
   Status process() override;
-  Status clean() override { return Status::OK; }
-  Status undo() override { return Status::OK; }
+  Status clean() override;
+  Status undo() override;
   Status precheck() override { return Status::OK; }
 
  private:
   bool UndoShareDirFor3x();
+  boost::filesystem::path backup_dir_;
 
   STEP_NAME(UndoPatchWgtStorageDirectories)
 };