Canonicalize by ::realpath on server side 97/72197/7
authorKyungwook Tak <k.tak@samsung.com>
Tue, 31 May 2016 07:05:51 +0000 (16:05 +0900)
committerKyungwook Tak <k.tak@samsung.com>
Tue, 31 May 2016 09:32:23 +0000 (18:32 +0900)
Client cannot call ::realpath because file scanning is not working with
client permission but server permission.

Client just make path to absolute (prepend current directory if relative
path comes in to parameter) and give them to server to get canonicalized
file set.

It's same to files_async and dirs_async but we need to erase
subdirectory in dirs_async case after canonicalization done.

Change-Id: I15ddd7e8816ee068c9e4439eea51bbe8c0a2602b
Signed-off-by: Kyungwook Tak <k.tak@samsung.com>
src/framework/client/canonicalize.cpp
src/framework/client/canonicalize.h
src/framework/client/content-screening.cpp
src/framework/common/command-id.h
src/framework/service/cs-logic.cpp
src/framework/service/cs-logic.h
src/framework/service/server-service.cpp
test/internals/CMakeLists.txt
test/internals/test-canonicalize.cpp [deleted file]
test/test-api-content-screening-async.cpp
test/test-common.h

index aa95d47..bf4ff99 100644 (file)
@@ -55,7 +55,7 @@ std::string getAbsolutePath(const std::string &path)
        return apath;
 }
 
-void canonicalizeDirSet(StrSet &dirset)
+void eraseSubdirectories(StrSet &dirset)
 {
        if (dirset.size() < 2)
                return;
index dc061a7..944b01d 100644 (file)
@@ -33,7 +33,7 @@ namespace Client {
 std::string getAbsolutePath(const std::string &path);
 
 // input directory set should contains resolved path only
-void canonicalizeDirSet(StrSet &dirset);
+void eraseSubdirectories(StrSet &dirset);
 
 } // namespace Client
 } // namespace Csr
index 2fa43b7..9cd5a04 100644 (file)
@@ -387,9 +387,26 @@ int csr_cs_scan_files_async(csr_cs_context_h handle, const char *file_paths[],
        }
 
        hExt->dispatchAsync([hExt, user_data, fileSet] {
+               auto ret = hExt->dispatch<std::pair<int, std::shared_ptr<StrSet>>>(
+                                       CommandId::CANONICALIZE_PATHS, *fileSet);
+
+               if (ret.first != CSR_ERROR_NONE) {
+                       if (hExt->m_cb.onError)
+                               hExt->m_cb.onError(ret.first, user_data);
+
+                       return;
+               }
+
+               std::shared_ptr<StrSet> canonicalizedFiles;
+
+               if (ret.second == nullptr)
+                       canonicalizedFiles = std::make_shared<StrSet>();
+               else
+                       canonicalizedFiles = std::move(ret.second);
+
                Client::AsyncLogic l(hExt, user_data, [&hExt] { return hExt->isStopped(); });
 
-               l.scanFiles(*fileSet).second();
+               l.scanFiles(*canonicalizedFiles).second();
        });
 
        return CSR_ERROR_NONE;
@@ -455,12 +472,29 @@ int csr_cs_scan_dirs_async(csr_cs_context_h handle, const char *dir_paths[],
                dirSet->insert(Client::getAbsolutePath(dir_paths[i]));
        }
 
-       Client::canonicalizeDirSet(*dirSet);
-
        hExt->dispatchAsync([hExt, user_data, dirSet] {
+               auto ret = hExt->dispatch<std::pair<int, std::shared_ptr<StrSet>>>(
+                                       CommandId::CANONICALIZE_PATHS, *dirSet);
+
+               if (ret.first != CSR_ERROR_NONE) {
+                       if (hExt->m_cb.onError)
+                               hExt->m_cb.onError(ret.first, user_data);
+
+                       return;
+               }
+
+               std::shared_ptr<StrSet> canonicalizedDirs;
+
+               if (ret.second == nullptr)
+                       canonicalizedDirs = std::make_shared<StrSet>();
+               else
+                       canonicalizedDirs = std::move(ret.second);
+
+               Client::eraseSubdirectories(*canonicalizedDirs);
+
                Client::AsyncLogic l(hExt, user_data, [&hExt] { return hExt->isStopped(); });
 
-               l.scanDirs(*dirSet).second();
+               l.scanDirs(*canonicalizedDirs).second();
        });
 
        return CSR_ERROR_NONE;
index 54d5e43..ee64d25 100644 (file)
@@ -34,7 +34,8 @@ enum class CommandId : int {
        GET_IGNORED         = 0x1103,
        GET_IGNORED_LIST    = 0x1104,
        GET_SCANNABLE_FILES = 0x1105,
-       SET_DIR_TIMESTAMP   = 0x1106,
+       CANONICALIZE_PATHS  = 0x1106,
+       SET_DIR_TIMESTAMP   = 0x1107,
        // handle result
        JUDGE_STATUS        = 0x1201,
 
index a77a056..7b780c9 100644 (file)
@@ -25,6 +25,8 @@
 #include <algorithm>
 #include <ctime>
 #include <climits>
+#include <cerrno>
+#include <unistd.h>
 
 #include "common/audit/logger.h"
 #include "service/type-converter.h"
@@ -445,6 +447,44 @@ RawBuffer CsLogic::getScannableFiles(const std::string &dir)
        EXCEPTION_GUARD_END
 }
 
+RawBuffer CsLogic::canonicalizePaths(const StrSet &paths)
+{
+       EXCEPTION_GUARD_START
+
+       if (this->m_db.getEngineState(CSR_ENGINE_CS) != CSR_STATE_ENABLE)
+               ThrowExc(EngineDisabled, "engine is disabled");
+
+       StrSet canonicalized;
+
+       for (const auto &path : paths) {
+               auto target = File::getPkgPath(path);
+               auto resolved = ::realpath(target.c_str(), nullptr);
+
+               if (resolved == nullptr) {
+                       const int err = errno;
+                       if (err == ENOENT)
+                               ThrowExc(FileDoNotExist, "File do not exist: " << target);
+                       else if (err == EACCES)
+                               ThrowExc(PermDenied, "Perm denied to get real path: " << target);
+                       else
+                               ThrowExc(FileSystemError, "Failed to get real path: " << target <<
+                                                " with errno: " << err);
+               }
+
+               std::string resolvedStr(resolved);
+               free(resolved);
+
+               if (canonicalized.find(resolvedStr) == canonicalized.end()) {
+                       INFO("Insert to canonicalized list: " << resolvedStr);
+                       canonicalized.emplace(std::move(resolvedStr));
+               }
+       }
+
+       return BinaryQueue::Serialize(CSR_ERROR_NONE, canonicalized).pop();
+
+       EXCEPTION_GUARD_END
+}
+
 RawBuffer CsLogic::setDirTimestamp(const std::string &dir, time_t ts)
 {
        EXCEPTION_GUARD_START
index f4cddc9..48939a9 100644 (file)
@@ -44,6 +44,7 @@ public:
        RawBuffer scanData(const CsContext &context, const RawBuffer &data);
        RawBuffer scanFile(const CsContext &context, const std::string &filepath);
        RawBuffer getScannableFiles(const std::string &dir);
+       RawBuffer canonicalizePaths(const StrSet &paths);
        RawBuffer setDirTimestamp(const std::string &dir, time_t ts);
        RawBuffer judgeStatus(const std::string &filepath, csr_cs_action_e action);
        RawBuffer getDetected(const std::string &filepath);
index 9c66b0a..f68dfed 100644 (file)
@@ -53,6 +53,7 @@ std::string cidToString(const CommandId &cid)
        CID_TOSTRING(GET_IGNORED);
        CID_TOSTRING(GET_IGNORED_LIST);
        CID_TOSTRING(GET_SCANNABLE_FILES);
+       CID_TOSTRING(CANONICALIZE_PATHS);
        CID_TOSTRING(SET_DIR_TIMESTAMP);
        CID_TOSTRING(JUDGE_STATUS);
 
@@ -137,6 +138,15 @@ RawBuffer ServerService::processCs(const ConnShPtr &conn, RawBuffer &data)
                return m_cslogic.getScannableFiles(dir);
        }
 
+       case CommandId::CANONICALIZE_PATHS: {
+               hasPermission(conn);
+
+               StrSet paths;
+               q.Deserialize(paths);
+
+               return m_cslogic.canonicalizePaths(paths);
+       }
+
        case CommandId::SET_DIR_TIMESTAMP: {
                hasPermission(conn);
 
index 2f8f198..d3ee64b 100644 (file)
@@ -40,7 +40,6 @@ SET(${TARGET_CSR_INTERNAL_TEST}_SRCS
        ${CSR_FW_SRC_PATH}/service/cs-loader.cpp
        ${CSR_FW_SRC_PATH}/service/wp-loader.cpp
        ${CSR_FW_SRC_PATH}/service/engine-error-converter.cpp
-       ${CSR_FW_SRC_PATH}/client/canonicalize.cpp
        ${CSR_FW_SRC_PATH}/ui/popup/package-info.cpp
 
        test-db.cpp
@@ -50,7 +49,6 @@ SET(${TARGET_CSR_INTERNAL_TEST}_SRCS
        test-api-engine-web-protection.cpp
        test-cs-loader.cpp
        test-wp-loader.cpp
-       test-canonicalize.cpp
        test-package-info.cpp
 
        test-main.cpp
diff --git a/test/internals/test-canonicalize.cpp b/test/internals/test-canonicalize.cpp
deleted file mode 100644 (file)
index be76649..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- *  Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License
- */
-/*
- * @file        test-canonicalize.cpp
- * @author      Kyungwook Tak (k.tak@samsung.com)
- * @version     1.0
- * @brief       file / directory set canonicalize unit test
- */
-#include <client/canonicalize.h>
-
-#include <system_error>
-#include <cerrno>
-#include <unistd.h>
-
-#include <boost/test/unit_test.hpp>
-
-#include "test-common.h"
-
-using namespace Csr;
-
-namespace {
-
-class ScopedChDir {
-public:
-       ScopedChDir(const std::string &dirpath)
-       {
-               if (getcwd(cdbuf, PATH_MAX + 1) == nullptr)
-                       throw std::system_error(errno, std::system_category(), "getcwd failed");
-
-               if (::chdir(dirpath.c_str()) == -1)
-                       throw std::system_error(errno, std::system_category(),
-                                                                       dirpath + " chdir failed");
-       }
-
-       ~ScopedChDir()
-       {
-               if (::chdir(cdbuf) == -1)
-                       throw std::system_error(errno, std::system_category(),
-                                                                       std::string(cdbuf) + " chdir failed");
-       }
-
-private:
-       char cdbuf[PATH_MAX + 1];
-};
-
-} // namespace anonymous
-
-BOOST_AUTO_TEST_SUITE(CANONICALIZE)
-
-BOOST_AUTO_TEST_CASE(get_absolute_path_file)
-{
-       EXCEPTION_GUARD_START
-
-       ScopedChDir chdir("/usr/bin");
-
-       std::string absolutePath = "/usr/bin/csr-server";
-
-       ASSERT_IF(Client::getAbsolutePath("/usr/bin/csr-server"), absolutePath);
-       ASSERT_IF(Client::getAbsolutePath("/usr/bin/../bin/csr-server"), absolutePath);
-       ASSERT_IF(Client::getAbsolutePath("/usr/bin/./csr-server"), absolutePath);
-       ASSERT_IF(Client::getAbsolutePath("csr-server"), absolutePath);
-
-       EXCEPTION_GUARD_END
-}
-
-BOOST_AUTO_TEST_CASE(get_absolute_path_dir)
-{
-       EXCEPTION_GUARD_START
-
-       ScopedChDir chdir("/usr/bin");
-
-       std::string absolutePath = "/usr/bin";
-
-       ASSERT_IF(Client::getAbsolutePath("/usr/bin/"), absolutePath);
-       ASSERT_IF(Client::getAbsolutePath("."), absolutePath);
-       ASSERT_IF(Client::getAbsolutePath("/usr/bin/../bin"), absolutePath);
-       ASSERT_IF(Client::getAbsolutePath("/usr/bin/./"), absolutePath);
-       ASSERT_IF(Client::getAbsolutePath("../bin/"), absolutePath);
-
-       EXCEPTION_GUARD_END
-}
-
-BOOST_AUTO_TEST_CASE(dir_set_1)
-{
-       EXCEPTION_GUARD_START
-
-       ScopedChDir chdir("/usr/bin");
-
-       StrSet dirset;
-
-       dirset.insert(Client::getAbsolutePath("/var/lib"));
-       dirset.insert(Client::getAbsolutePath("/bin"));
-       dirset.insert(Client::getAbsolutePath("/"));
-       dirset.insert(Client::getAbsolutePath("/opt"));
-       dirset.insert(Client::getAbsolutePath("/usr/bin"));
-
-       Client::canonicalizeDirSet(dirset);
-
-       ASSERT_IF(dirset.size(), std::size_t(1));
-       ASSERT_IF(dirset.count("/"), std::size_t(1));
-
-       EXCEPTION_GUARD_END
-}
-
-BOOST_AUTO_TEST_CASE(dir_set_2)
-{
-       EXCEPTION_GUARD_START
-
-       ScopedChDir chdir("/usr/bin");
-
-       StrSet dirset;
-
-       dirset.insert(Client::getAbsolutePath("/usr/share"));
-       dirset.insert(Client::getAbsolutePath("/usr/lib"));
-       dirset.insert(Client::getAbsolutePath("/usr"));
-       dirset.insert(Client::getAbsolutePath("/usr/etc"));
-       dirset.insert(Client::getAbsolutePath("/opt/share"));
-       dirset.insert(Client::getAbsolutePath("/opt/dbspace"));
-
-       Client::canonicalizeDirSet(dirset);
-
-       ASSERT_IF(dirset.size(), std::size_t(3));
-       ASSERT_IF(dirset.count("/usr"), std::size_t(1));
-       ASSERT_IF(dirset.count("/opt/share"), std::size_t(1));
-       ASSERT_IF(dirset.count("/opt/dbspace"), std::size_t(1));
-
-       EXCEPTION_GUARD_END
-}
-
-BOOST_AUTO_TEST_SUITE_END()
index ac79a36..e6ada81 100644 (file)
  *  limitations under the License
  */
 /*
- * @file        test-api-content-screening.cpp
+ * @file        test-api-content-screening-async.cpp
  * @author      Kyungwook Tak (k.tak@samsung.com)
  * @version     1.0
- * @brief       CSR Content screening API test
+ * @brief       CSR Content screening async API test
  */
 #include <csr-content-screening.h>
 
 #include <condition_variable>
 #include <thread>
 #include <mutex>
+#include <vector>
 #include <boost/test/unit_test.hpp>
 
 #include "test-common.h"
@@ -49,12 +50,14 @@ namespace {
 
 struct AsyncTestContext {
        std::mutex m;
+       std::mutex m_vec;
        std::condition_variable cv;
        int scannedCnt;
        int detectedCnt;
        int completedCnt;
        int cancelledCnt;
        int errorCnt;
+       std::vector<std::string> scannedList;
        std::vector<csr_cs_malware_h> detectedList;
        int errorCode;
 
@@ -70,7 +73,11 @@ void on_scanned(const char *file, void *userdata)
 {
        BOOST_MESSAGE("on_scanned. file[" << file << "] scanned!");
        auto ctx = reinterpret_cast<AsyncTestContext *>(userdata);
+
+       std::lock_guard<std::mutex> l(ctx->m_vec);
+
        ctx->scannedCnt++;
+       ctx->scannedList.push_back(file);
 }
 
 void on_detected(csr_cs_malware_h detected, void *userdata)
@@ -79,6 +86,9 @@ void on_detected(csr_cs_malware_h detected, void *userdata)
        ASSERT_IF(csr_cs_malware_get_file_name(detected, &file_name.ptr), CSR_ERROR_NONE);
        BOOST_MESSAGE("on_detected. file[" << file_name.ptr << "] detected!");
        auto ctx = reinterpret_cast<AsyncTestContext *>(userdata);
+
+       std::lock_guard<std::mutex> l(ctx->m_vec);
+
        ctx->detectedCnt++;
        ctx->detectedList.push_back(detected);
 }
@@ -87,6 +97,7 @@ void on_error(int ec, void *userdata)
 {
        BOOST_MESSAGE("on_error. async request done with error code[" << ec << "]");
        auto ctx = reinterpret_cast<AsyncTestContext *>(userdata);
+
        ctx->errorCnt++;
        ctx->errorCode = ec;
        ctx->cv.notify_one();
@@ -787,6 +798,84 @@ BOOST_AUTO_TEST_CASE(delta_scan_changed_after_scan)
        EXCEPTION_GUARD_END
 }
 
+BOOST_AUTO_TEST_CASE(canonicalize_files_absolute_path)
+{
+       EXCEPTION_GUARD_START
+
+       Test::initialize_db();
+
+       auto c = Test::Context<csr_cs_context_h>();
+       auto context = c.get();
+
+       install_test_files();
+
+       set_default_callback(context);
+
+       // four files are all same as realpath.
+       const char *files[4] = {
+               TEST_FILE_NORMAL,
+               TEST_DIR "/./test_normal_file",
+               TEST_DIR "/.././././csr-test/test_normal_file",
+               TEST_DIR "/././.././csr-test/test_normal_file"
+       };
+
+       AsyncTestContext testCtx;
+
+       ASSERT_IF(csr_cs_scan_files_async(context, files, sizeof(files) / sizeof(const char *),
+                                                                         &testCtx),
+                         CSR_ERROR_NONE);
+
+       std::unique_lock<std::mutex> l(testCtx.m);
+       testCtx.cv.wait(l);
+       l.unlock();
+
+       ASSERT_CALLBACK(testCtx, 1, 0, 1, 0, 0);
+       ASSERT_IF(testCtx.scannedList.size(), static_cast<std::size_t>(1));
+       ASSERT_IF(testCtx.scannedList.front(), static_cast<const char *>(TEST_FILE_NORMAL));
+
+       EXCEPTION_GUARD_END
+}
+
+BOOST_AUTO_TEST_CASE(canonicalize_files_relative_path)
+{
+       EXCEPTION_GUARD_START
+
+       Test::initialize_db();
+
+       auto c = Test::Context<csr_cs_context_h>();
+       auto context = c.get();
+
+       install_test_files();
+
+       set_default_callback(context);
+
+       // four files are all same as realpath.
+       const char *files[4] = {
+               "test_normal_file",
+               "./test_normal_file",
+               ".././././csr-test/test_normal_file",
+               "././.././csr-test/test_normal_file"
+       };
+
+       AsyncTestContext testCtx;
+
+       Test::ScopedChDir scopedCd(TEST_DIR);
+
+       ASSERT_IF(csr_cs_scan_files_async(context, files, sizeof(files) / sizeof(const char *),
+                                                                         &testCtx),
+                         CSR_ERROR_NONE);
+
+       std::unique_lock<std::mutex> l(testCtx.m);
+       testCtx.cv.wait(l);
+       l.unlock();
+
+       ASSERT_CALLBACK(testCtx, 1, 0, 1, 0, 0);
+       ASSERT_IF(testCtx.scannedList.size(), static_cast<std::size_t>(1));
+       ASSERT_IF(testCtx.scannedList.front(), static_cast<const char *>(TEST_FILE_NORMAL));
+
+       EXCEPTION_GUARD_END
+}
+
 BOOST_AUTO_TEST_CASE(multiple_async_dispatch_negative)
 {
        EXCEPTION_GUARD_START
index 481e5ab..b70f853 100644 (file)
@@ -28,6 +28,9 @@
 #include <typeinfo>
 #include <string>
 #include <cstring>
+#include <cerrno>
+#include <system_error>
+#include <unistd.h>
 
 #include <boost/test/unit_test.hpp>
 
@@ -177,6 +180,29 @@ struct ScopedCstr {
        }
 };
 
+class ScopedChDir {
+public:
+       ScopedChDir(const std::string &dirpath)
+       {
+               if (::getcwd(cdbuf, PATH_MAX + 1) == nullptr)
+                       throw std::system_error(errno, std::system_category(), "getcwd failed");
+
+               if (::chdir(dirpath.c_str()) == -1)
+                       throw std::system_error(errno, std::system_category(),
+                                                                       dirpath + " chdir failed");
+       }
+
+       ~ScopedChDir()
+       {
+               if (::chdir(cdbuf) == -1)
+                       throw std::system_error(errno, std::system_category(),
+                                                                       std::string(cdbuf) + " chdir failed");
+       }
+
+private:
+       char cdbuf[PATH_MAX + 1];
+};
+
 template <typename T>
 class Context {
 public: