Fix smack deny issue while updating pkg 23/168823/15
authorJunghyun Yeon <jungh.yeon@samsung.com>
Wed, 31 Jan 2018 07:52:05 +0000 (16:52 +0900)
committerJunghyun Yeon <jungh.yeon@samsung.com>
Wed, 7 Feb 2018 08:57:50 +0000 (17:57 +0900)
- When certain pkg is updating and some other application
  tries to access its shared/res directory, it may cause
  smack deny if file has copied but security registration is
  not performed.
- This patch preserves shared and shared/res directory to
  preserve its smack label and this will transmuted into
  files and directories which will be copied into it.

Change-Id: I7eed21df0387ad969d6b8a13f0c269e1022db8e2
Signed-off-by: Junghyun Yeon <jungh.yeon@samsung.com>
src/common/step/backup/step_copy_backup.cc

index 4319f213755091747216b54e058ad2e09dc59336..0470e8b5b23c3e5128b8dec93d68f71ad8f134b5 100644 (file)
 
 #include "common/paths.h"
 #include "common/utils/file_util.h"
+#include "common/utils/user_util.h"
 #include "common/shared_dirs.h"
 
+namespace bf = boost::filesystem;
+namespace bs = boost::system;
+namespace ci = common_installer;
+
 namespace {
 
 const char kExternalMemoryMountPoint[] = ".mmc";
 
+bool RemoveContents(const bf::path& path) {
+  for (bf::directory_iterator iter(path);
+      iter != bf::directory_iterator(); ++iter) {
+    if (!ci::RemoveAll(iter->path()))
+      return false;
+  }
+  return true;
+}
+
+bool BackupContents(const bf::path& src, const bf::path& backup_path) {
+  if (!ci::CopyDir(src, backup_path,
+      ci::FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS, false))
+    return false;
+  for (bf::directory_iterator iter(src);
+      iter != bf::directory_iterator(); ++iter) {
+    if (iter->path().filename() == "res") {
+      if (!RemoveContents(iter->path()))
+        return false;
+      continue;
+    }
+
+    if (!ci::RemoveAll(iter->path()))
+      return false;
+  }
+
+  return true;
+}
+
 }  // namespace
 
 namespace common_installer {
 namespace backup {
 
-namespace bf = boost::filesystem;
-namespace bs = boost::system;
-
 Step::Status StepCopyBackup::precheck() {
   if (context_->pkgid.get().empty()) {
     LOG(ERROR) << "pkgid attribute is empty";
@@ -56,7 +86,6 @@ Step::Status StepCopyBackup::process() {
     return Status::APP_DIR_ERROR;
 
   RemoveContent();
-
   return Status::OK;
 }
 
@@ -122,6 +151,11 @@ bool StepCopyBackup::Backup() {
       }
     }
 
+    if (iter->path() == context_->GetPkgPath() / "shared") {
+      if (!BackupContents(iter->path(), backup_path_ / "shared"))
+        return false;
+      continue;
+    }
     if (bf::is_directory(iter->path())) {
       if (!MoveDir(iter->path(), backup_path_ / iter->path().filename())) {
         LOG(ERROR) << "Fail to backup package directory of: " << iter->path();
@@ -186,13 +220,39 @@ bool StepCopyBackup::NewContent() {
     LOG(ERROR) << "Cannot create package directory";
     return false;
   }
-  if (!MoveDir(context_->unpacked_dir_path.get(), install_path_,
-               FSFlag::FS_MERGE_SKIP)) {
-    LOG(ERROR) << "Fail to copy tmp dir: " << context_->unpacked_dir_path.get()
-               << " to dst dir: " << install_path_;
-    return false;
+  for (bf::directory_iterator iter(context_->unpacked_dir_path.get());
+       iter != bf::directory_iterator(); ++iter) {
+    if (bf::is_directory(iter->path())) {
+      if (!MoveDir(iter->path(), install_path_ / iter->path().filename(),
+        FS_MERGE_SKIP)) {
+        LOG(ERROR) << "Fail to copy tmp dir: " << iter->path()
+                   << " to dst dir: " << install_path_;
+        return false;
+      }
+    } else {
+      if (!MoveFile(iter->path(), install_path_ / iter->path().filename())) {
+        LOG(ERROR) << "Fail to copy tmp dir: " << iter->path()
+                   << " to dst dir: " << install_path_;
+        return false;
+      }
+    }
   }
 
+  // If other application tries to access shared/res of package being installed,
+  // it will be failed due to permission deny. Set its permission before
+  // StepChangeOwnershipAndPermission to prevent it.
+  uid_t uid = context_->uid.get();
+  boost::optional<gid_t> gid = common_installer::GetGidByUid(uid);
+  if (!gid) {
+    LOG(ERROR) << "Failed to get gid";
+    return false;
+  }
+  if (bf::exists(install_path_ / "shared/res") &&
+      !common_installer::SetOwnershipAll(
+          install_path_ / "shared/res", uid, *gid)) {
+    LOG(ERROR) << "Failed to set ownership";
+    return false;
+  }
   LOG(INFO) << "Successfully move: " << context_->unpacked_dir_path.get()
             << " to: " << install_path_ << " directory";