From: Kyungwook Tak Date: Tue, 31 May 2016 07:05:51 +0000 (+0900) Subject: Canonicalize by ::realpath on server side X-Git-Tag: accepted/tizen/common/20160614.143943^2~72 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F97%2F72197%2F7;p=platform%2Fupstream%2Fcsr-framework.git Canonicalize by ::realpath on server side 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 --- diff --git a/src/framework/client/canonicalize.cpp b/src/framework/client/canonicalize.cpp index aa95d47..bf4ff99 100644 --- a/src/framework/client/canonicalize.cpp +++ b/src/framework/client/canonicalize.cpp @@ -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; diff --git a/src/framework/client/canonicalize.h b/src/framework/client/canonicalize.h index dc061a7..944b01d 100644 --- a/src/framework/client/canonicalize.h +++ b/src/framework/client/canonicalize.h @@ -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 diff --git a/src/framework/client/content-screening.cpp b/src/framework/client/content-screening.cpp index 2fa43b7..9cd5a04 100644 --- a/src/framework/client/content-screening.cpp +++ b/src/framework/client/content-screening.cpp @@ -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>>( + 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 canonicalizedFiles; + + if (ret.second == nullptr) + canonicalizedFiles = std::make_shared(); + 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>>( + 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 canonicalizedDirs; + + if (ret.second == nullptr) + canonicalizedDirs = std::make_shared(); + 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; diff --git a/src/framework/common/command-id.h b/src/framework/common/command-id.h index 54d5e43..ee64d25 100644 --- a/src/framework/common/command-id.h +++ b/src/framework/common/command-id.h @@ -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, diff --git a/src/framework/service/cs-logic.cpp b/src/framework/service/cs-logic.cpp index a77a056..7b780c9 100644 --- a/src/framework/service/cs-logic.cpp +++ b/src/framework/service/cs-logic.cpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include #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 diff --git a/src/framework/service/cs-logic.h b/src/framework/service/cs-logic.h index f4cddc9..48939a9 100644 --- a/src/framework/service/cs-logic.h +++ b/src/framework/service/cs-logic.h @@ -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); diff --git a/src/framework/service/server-service.cpp b/src/framework/service/server-service.cpp index 9c66b0a..f68dfed 100644 --- a/src/framework/service/server-service.cpp +++ b/src/framework/service/server-service.cpp @@ -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); diff --git a/test/internals/CMakeLists.txt b/test/internals/CMakeLists.txt index 2f8f198..d3ee64b 100644 --- a/test/internals/CMakeLists.txt +++ b/test/internals/CMakeLists.txt @@ -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 index be76649..0000000 --- a/test/internals/test-canonicalize.cpp +++ /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 - -#include -#include -#include - -#include - -#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() diff --git a/test/test-api-content-screening-async.cpp b/test/test-api-content-screening-async.cpp index ac79a36..e6ada81 100644 --- a/test/test-api-content-screening-async.cpp +++ b/test/test-api-content-screening-async.cpp @@ -14,16 +14,17 @@ * 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 #include #include #include +#include #include #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 scannedList; std::vector 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(userdata); + + std::lock_guard 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(userdata); + + std::lock_guard 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(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(); + 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 l(testCtx.m); + testCtx.cv.wait(l); + l.unlock(); + + ASSERT_CALLBACK(testCtx, 1, 0, 1, 0, 0); + ASSERT_IF(testCtx.scannedList.size(), static_cast(1)); + ASSERT_IF(testCtx.scannedList.front(), static_cast(TEST_FILE_NORMAL)); + + EXCEPTION_GUARD_END +} + +BOOST_AUTO_TEST_CASE(canonicalize_files_relative_path) +{ + EXCEPTION_GUARD_START + + Test::initialize_db(); + + auto c = Test::Context(); + 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 l(testCtx.m); + testCtx.cv.wait(l); + l.unlock(); + + ASSERT_CALLBACK(testCtx, 1, 0, 1, 0, 0); + ASSERT_IF(testCtx.scannedList.size(), static_cast(1)); + ASSERT_IF(testCtx.scannedList.front(), static_cast(TEST_FILE_NORMAL)); + + EXCEPTION_GUARD_END +} + BOOST_AUTO_TEST_CASE(multiple_async_dispatch_negative) { EXCEPTION_GUARD_START diff --git a/test/test-common.h b/test/test-common.h index 481e5ab..b70f853 100644 --- a/test/test-common.h +++ b/test/test-common.h @@ -28,6 +28,9 @@ #include #include #include +#include +#include +#include #include @@ -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 class Context { public: