Add checking routine to prevent path traverse attack 46/262946/3
authorJunghyun Yeon <jungh.yeon@samsung.com>
Tue, 24 Aug 2021 01:41:02 +0000 (10:41 +0900)
committerJunghyun Yeon <jungh.yeon@samsung.com>
Tue, 24 Aug 2021 03:08:11 +0000 (12:08 +0900)
Change-Id: Ie90df0c9d1075725870cdce7c86f7c1a6c5b703a
Signed-off-by: Junghyun Yeon <jungh.yeon@samsung.com>
src/res-copy/include/param_checker.hh
src/res-copy/src/param_checker.cc
tests/unit_tests/res-copy/src/test_param_checker.cc

index 437a0e2..7434863 100644 (file)
@@ -43,6 +43,7 @@ class ParamChecker {
 
   void SetRequestType(std::string key);
   bool ValidatePkgID();
+  bool ValidatePathList();
 };
 
 }  // res_handler
index d44ca85..72083a0 100644 (file)
 namespace bs = boost::system;
 namespace bpo = boost::program_options;
 
+namespace {
+
+bool IsPathTraversal(const std::string& path) {
+  if (path.size() == 0)
+    return true;
+
+  if (path.find("..", 0) != std::string::npos) {
+    LOG(ERROR) << "Invalid path : " << path;
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
 namespace res_handler {
 
 ParamChecker::ParamChecker(int argc, char* argv[]) {
@@ -110,12 +126,8 @@ bool ParamChecker::Validate() {
   if (!ValidatePkgID())
     return false;
 
-  if (req_type_ != ReqType::REQ_TYPE_UNINSTALL) {
-    if (path_info_list_.size() == 0) {
-      LOG(ERROR) << "Path is not given";
-      return false;
-    }
-  }
+  if (!ValidatePathList())
+    return false;
 
   return true;
 }
@@ -140,4 +152,21 @@ bool ParamChecker::ValidatePkgID() {
   return true;
 }
 
+bool ParamChecker::ValidatePathList() {
+  if (req_type_ != ReqType::REQ_TYPE_UNINSTALL) {
+    if (path_info_list_.size() == 0) {
+      LOG(ERROR) << "Path is not given";
+      return false;
+    }
+  }
+
+  for (auto& path_info : path_info_list_) {
+    if (!IsPathTraversal(path_info.GetSrcPath()) ||
+        !IsPathTraversal(path_info.GetDstPath()))
+      return false;
+  }
+
+  return true;
+}
+
 }  // namespace res_handler
index 69163e9..b76b45d 100644 (file)
@@ -45,10 +45,12 @@ class ParamCheckerTest : public TestFixture {
   virtual ~ParamCheckerTest() {}
 
   virtual void SetUp() {
-    EXPECT_CALL(GetMock<PkgMgrInfoMock>(), pkgmgrinfo_pkginfo_get_usr_pkginfo(_, _, _))
+    EXPECT_CALL(GetMock<PkgMgrInfoMock>(),
+            pkgmgrinfo_pkginfo_get_usr_pkginfo(_, _, _))
             .WillRepeatedly(Return(0));
-    EXPECT_CALL(GetMock<PkgMgrInfoMock>(), pkgmgrinfo_pkginfo_destroy_pkginfo(_))
-                .WillRepeatedly(Return(0)) ;
+    EXPECT_CALL(GetMock<PkgMgrInfoMock>(),
+            pkgmgrinfo_pkginfo_destroy_pkginfo(_))
+            .WillRepeatedly(Return(0)) ;
   }
   virtual void TearDown() {}
 };
@@ -70,8 +72,8 @@ TEST_F(ParamCheckerTest, PkgIDNotGiven) {
 }
 
 TEST_F(ParamCheckerTest, CopyRes) {
-  const char *argv[] = { "/bin/res-copy", "--uid", "5001", "-p", "srcpath", "dstpath",
-      "--copy", "org.test.targetpkgid", nullptr};
+  const char *argv[] = { "/bin/res-copy", "--uid", "5001",
+      "-p", "srcpath", "dstpath", "--copy", "org.test.targetpkgid", nullptr};
 
   ParamChecker checker(8, (char**)argv);
 
@@ -102,7 +104,8 @@ TEST_F(ParamCheckerTest, DeleteRes) {
   ParamChecker checker(5, (char**)argv);
 
   EXPECT_EQ(checker.Validate(), true);
-  EXPECT_EQ(checker.GetRequestType(), res_handler::ReqType::REQ_TYPE_UNINSTALL);
+  EXPECT_EQ(checker.GetRequestType(),
+      res_handler::ReqType::REQ_TYPE_UNINSTALL);
   EXPECT_EQ(checker.GetPkgID(), "org.test.targetpkgid");
   EXPECT_EQ(checker.GetPathList().size(), 0);
   EXPECT_EQ(checker.GetUID(), 5001);
@@ -131,3 +134,33 @@ TEST_F(ParamCheckerTest, PathNotGiven) {
 
   EXPECT_EQ(checker.Validate(), false);
 }
+
+TEST_F(ParamCheckerTest, CopyRes_SrcPathTraverseAttack) {
+  const char *argv[] = { "/bin/res-copy", "--uid",
+      "5001", "-p", "data/../../attackpath", "dstpath",
+      "--copy", "org.test.targetpkgid", nullptr};
+
+  ParamChecker checker(8, (char**)argv);
+
+  EXPECT_FALSE(checker.Validate());
+}
+
+TEST_F(ParamCheckerTest, CopyRes_DstPathTraverseAttack) {
+  const char *argv[] = { "/bin/res-copy", "--uid",
+      "5001", "-p", "data/normal_path", "../../attackpath",
+      "--copy", "org.test.targetpkgid", nullptr};
+
+  ParamChecker checker(8, (char**)argv);
+
+  EXPECT_FALSE(checker.Validate());
+}
+
+TEST_F(ParamCheckerTest, RemoveRes_PathTraverseAttack) {
+  const char *argv[] = { "/bin/res-copy", "--uid",
+      "5001", "-p", "../../../attackpath", "",
+      "--remove", "org.test.targetpkgid", nullptr};
+
+  ParamChecker checker(8, (char**)argv);
+
+  EXPECT_FALSE(checker.Validate());
+}