summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyungwook Tak <k.tak@samsung.com>2016-06-27 15:30:53 +0900
committerkyungwook tak <k.tak@samsung.com>2016-07-04 00:23:25 -0700
commit9a0e9a7454565598f4f6378417863f637764d766 (patch)
tree281f0636a94b06a5cae96e71b2a52f63dbbb97fc
parentefade4380b460acbab9e0786e1f533a2451e3268 (diff)
downloadcsr-framework-9a0e9a7454565598f4f6378417863f637764d766.tar.gz
csr-framework-9a0e9a7454565598f4f6378417863f637764d766.tar.bz2
csr-framework-9a0e9a7454565598f4f6378417863f637764d766.zip
client-server conversation arch for async scan
Async operation process AS-IS 1) getting scannable file list from server 2) dispatch scan file operation per item in list TO-BE 1) dispatch async scanning with files/dirs list by client 2) Client receives event only when malware detected by server unless file scanned callback is registered. IPC time is much more lower than before because IPC isn't needed for file scanned without malware when callback isn't registered. Memory usage on client side is much less than before because client doesn't receive a bunch of scannable file list. Client only receives event when callback call needed or operation completed. Change-Id: I0c913a2fbdf75c2abe99cdf6d757fdb0f264145d Signed-off-by: Kyungwook Tak <k.tak@samsung.com>
-rw-r--r--src/framework/client/async-logic.cpp143
-rw-r--r--src/framework/client/async-logic.h23
-rw-r--r--src/framework/client/canonicalize.cpp27
-rw-r--r--src/framework/client/canonicalize.h3
-rw-r--r--src/framework/client/content-screening.cpp114
-rw-r--r--src/framework/client/handle.h9
-rw-r--r--src/framework/client/utils.cpp4
-rw-r--r--src/framework/common/async-protocol.h35
-rw-r--r--src/framework/common/command-id.h5
-rw-r--r--src/framework/common/cs-context.cpp21
-rw-r--r--src/framework/common/cs-context.h2
-rw-r--r--src/framework/common/dispatcher.h17
-rw-r--r--src/framework/common/serialization.h53
-rw-r--r--src/framework/common/socket.cpp10
-rw-r--r--src/framework/db/manager.cpp11
-rw-r--r--src/framework/db/manager.h5
-rw-r--r--src/framework/service/cs-logic.cpp462
-rw-r--r--src/framework/service/cs-logic.h21
-rw-r--r--src/framework/service/file-system.cpp5
-rw-r--r--src/framework/service/server-service.cpp66
-rw-r--r--test/internals/test-db.cpp8
-rw-r--r--test/test-api-content-screening-async.cpp4
22 files changed, 604 insertions, 444 deletions
diff --git a/src/framework/client/async-logic.cpp b/src/framework/client/async-logic.cpp
index 0dec60a..454c184 100644
--- a/src/framework/client/async-logic.cpp
+++ b/src/framework/client/async-logic.cpp
@@ -26,120 +26,95 @@
#include "common/exception.h"
#include "common/cs-detected.h"
+#include "common/async-protocol.h"
#include "common/audit/logger.h"
namespace Csr {
namespace Client {
AsyncLogic::AsyncLogic(HandleExt *handle, void *userdata) :
- m_handle(handle),
- m_ctx(new CsContext),
- m_cb(handle->m_cb),
- m_userdata(userdata)
+ m_handle(handle), m_userdata(userdata)
{
- // disable ask user option for async request for now
- copyKvp<int>(CsContext::Key::CoreUsage);
- copyKvp<std::string>(CsContext::Key::PopupMessage);
- copyKvp<bool>(CsContext::Key::ScanOnCloud);
}
AsyncLogic::~AsyncLogic()
{
- for (auto &resultPtr : this->m_results)
- this->m_handle->add(std::move(resultPtr));
}
void AsyncLogic::scanDirs(const StrSet &dirs)
{
- for (const auto &dir : dirs)
- this->scanDir(dir);
+ this->scanHelper(CommandId::SCAN_DIRS_ASYNC, dirs);
}
-void AsyncLogic::scanDir(const std::string &dir)
+void AsyncLogic::scanFiles(const StrSet &files)
{
- auto startTime = ::time(nullptr);
+ this->scanHelper(CommandId::SCAN_FILES_ASYNC, files);
+}
- if (this->m_handle->isStopped())
- ThrowExcInfo(-999, "Async operation cancelled!");
+void AsyncLogic::scanHelper(const CommandId &id, const StrSet &s)
+{
+ auto ret = this->m_handle->dispatch<int>(id, *(this->m_handle->getContext()), s);
- // Already scanned files are included in history. it'll be skipped later
- // on server side by every single scan_file request.
- auto retFiles = this->m_handle->dispatch<std::pair<int, std::shared_ptr<StrSet>>>(
- CommandId::GET_SCANNABLE_FILES, dir);
+ if (ret != ASYNC_EVENT_START)
+ ThrowExc(ret, "Error on async scan. ret: " << ret);
- if (retFiles.first == -999) {
- ThrowExcInfo(-999, "Async op cancelled!");
- } else if (retFiles.first != CSR_ERROR_NONE) {
- ThrowExc(retFiles.first, "Error to get scannalbe files. "
- "dir: " << dir << " ret: " << retFiles.first);
- }
+ bool isDone = false;
- if (retFiles.second == nullptr) {
- INFO("No scannable file exist on dir: " << dir);
- return;
- }
+ DEBUG("loop for waiting server event start!!");
-#ifdef TIZEN_DEBUG_ENABLE
- DEBUG("scannable file list in dir[" << dir <<
- "], count[" << retFiles.second->size() << "]:");
- size_t count = 0;
- for (const auto &file : *(retFiles.second))
- DEBUG(std::to_string(++count) << " : " << file);
-#endif
-
- // Let's start scan files!
- this->scanFiles(*(retFiles.second));
-
- auto ts64 = static_cast<int64_t>(startTime);
-
- auto ret = this->m_handle->dispatch<int>(CommandId::SET_DIR_TIMESTAMP, dir, ts64);
- if (ret != CSR_ERROR_NONE)
- ERROR("Failed to set dir timestamp after scan dir[" << dir << "] with "
- "ec[" << ret << "] This is server error and not affects to "
- "client / scan result when it doesn't comes to delta scanning... "
- "So just ignore this error on client side.");
-}
+ while (!isDone) {
+ auto event = this->m_handle->revent<int>();
-void AsyncLogic::scanFiles(const StrSet &fileSet)
-{
- for (const auto &file : fileSet) {
- if (this->m_handle->isStopped())
- ThrowExcInfo(-999, "Async op cancelled!");
-
- auto ret = this->m_handle->dispatch<std::pair<int, CsDetected *>>(
- CommandId::SCAN_FILE, this->m_ctx, file);
-
- // for auto memory deleting in case of exception
- ResultPtr resultPtr(ret.second);
-
- // ignore all file-system related error in async operation.
- if (ret.first == CSR_ERROR_FILE_DO_NOT_EXIST ||
- ret.first == CSR_ERROR_FILE_CHANGED ||
- ret.first == CSR_ERROR_FILE_SYSTEM) {
- WARN("File system related error code returned when scan files async."
- " Ignore all file-system related error in async operation because"
- " scan file list has been provided by server."
- " file: " << file << " ret: " << ret.first);
- continue;
+ DEBUG("event received: " << event);
+
+ switch (event) {
+ case ASYNC_EVENT_MALWARE_NONE: {
+ DEBUG("ASYNC_EVENT_MALWARE_NONE comes in!");
+ auto targetName = this->m_handle->revent<std::string>();
+
+ if (targetName.empty()) {
+ ERROR("scanned event received but target name is empty");
+ break;
+ }
+
+ if (this->m_handle->m_cb.onScanned != nullptr)
+ this->m_handle->m_cb.onScanned(targetName.c_str(), this->m_userdata);
+
+ break;
}
- if (ret.first != CSR_ERROR_NONE)
- ThrowExc(ret.first, "Error on async scan. ret: " << ret.first <<
- " while scan file: " << file);
+ case ASYNC_EVENT_MALWARE_DETECTED: {
+ DEBUG("ASYNC_EVENT_MALWARE_DETECTED comes in!");
+ auto malware = this->m_handle->revent<CsDetected *>();
+
+ if (malware == nullptr) {
+ ERROR("malware detected event received but handle is null");
+ break;
+ }
- if (ret.second) {
- INFO("[Detected] file[" << file << "]");
- this->m_results.emplace_back(std::move(resultPtr));
+ ResultPtr resultPtr(malware);
- if (this->m_cb.onDetected != nullptr)
- this->m_cb.onDetected(reinterpret_cast<csr_cs_malware_h>(ret.second),
- this->m_userdata);
- } else {
- DEBUG("[Scanned] file[" << file << "]");
+ if (this->m_handle->m_cb.onDetected != nullptr) {
+ this->m_handle->add(std::move(resultPtr));
+ this->m_handle->m_cb.onDetected(
+ reinterpret_cast<csr_cs_malware_h>(malware), this->m_userdata);
+ }
+
+ break;
+ }
- if (this->m_cb.onScanned != nullptr)
- this->m_cb.onScanned(file.c_str(), this->m_userdata);
+ case ASYNC_EVENT_COMPLETE: {
+ DEBUG("Async operation completed");
+ isDone = true;
+ break;
}
+
+ default:
+ ThrowExc(event, "Error on async scan! ec: " << event);
+ }
+
+ if (this->m_handle->isStopped())
+ ThrowExcInfo(ASYNC_EVENT_CANCEL, "Async op cancelled!");
}
}
diff --git a/src/framework/client/async-logic.h b/src/framework/client/async-logic.h
index a1294ec..0136074 100644
--- a/src/framework/client/async-logic.h
+++ b/src/framework/client/async-logic.h
@@ -21,12 +21,8 @@
*/
#pragma once
-#include <memory>
-#include <atomic>
-
#include "common/types.h"
-#include "common/cs-context.h"
-#include "client/callback.h"
+#include "common/command-id.h"
#include "client/handle-ext.h"
namespace Csr {
@@ -38,32 +34,17 @@ public:
virtual ~AsyncLogic();
void scanFiles(const StrSet &files);
- void scanDir(const std::string &dir);
void scanDirs(const StrSet &dirs);
void stop(void);
private:
- template<typename T>
- void copyKvp(CsContext::Key);
+ void scanHelper(const CommandId &id, const StrSet &s);
HandleExt *m_handle; // for registering results for auto-release
- ContextPtr m_ctx;
- std::vector<ResultPtr> m_results;
-
- Callback m_cb;
void *m_userdata;
};
-template<typename T>
-void AsyncLogic::copyKvp(CsContext::Key key)
-{
- T value;
-
- this->m_handle->getContext()->get(static_cast<int>(key), value);
- this->m_ctx->set(static_cast<int>(key), value);
-}
-
}
}
diff --git a/src/framework/client/canonicalize.cpp b/src/framework/client/canonicalize.cpp
index 4846691..bb412dd 100644
--- a/src/framework/client/canonicalize.cpp
+++ b/src/framework/client/canonicalize.cpp
@@ -55,32 +55,5 @@ std::string getAbsolutePath(const std::string &path)
return apath;
}
-void eraseSubdirectories(StrSet &dirset)
-{
- if (dirset.size() < 2)
- return;
-
- for (auto it = dirset.begin(); it != dirset.end(); ++it) {
- auto itsub = it;
- ++itsub;
- while (true) {
- if (itsub == dirset.end())
- break;
-
- auto itl = it->length();
- auto itsubl = itsub->length();
-
- if (itl + 1 >= itsubl || // to short to be sub-directory
- itsub->compare(0, itl, *it) != 0 || // prefix isn't matched
- (*it != "/" && itsub->at(itl) != '/')) { // has '/' at the end of prefix
- ++itsub;
- continue;
- }
-
- itsub = dirset.erase(itsub);
- }
- }
-}
-
}
}
diff --git a/src/framework/client/canonicalize.h b/src/framework/client/canonicalize.h
index 944b01d..16427e3 100644
--- a/src/framework/client/canonicalize.h
+++ b/src/framework/client/canonicalize.h
@@ -32,8 +32,5 @@ namespace Client {
// based on linux function: realpath
std::string getAbsolutePath(const std::string &path);
-// input directory set should contains resolved path only
-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 98f9a5c..61684c0 100644
--- a/src/framework/client/content-screening.cpp
+++ b/src/framework/client/content-screening.cpp
@@ -34,6 +34,7 @@
#include "common/cs-context.h"
#include "common/cs-detected.h"
#include "common/command-id.h"
+#include "common/async-protocol.h"
#include "common/audit/logger.h"
using namespace Csr;
@@ -228,10 +229,14 @@ int csr_cs_scan_data(csr_cs_context_h handle, const unsigned char *data,
hExt->getContext(),
RawBuffer(data, data + length));
- if (ret.second)
- hExt->add(ResultPtr(ret.second));
+ ResultPtr resultPtr(ret.second);
- *malware = reinterpret_cast<csr_cs_malware_h>(ret.second);
+ if (ret.second && !ret.second->malwareName.empty()) {
+ hExt->add(std::move(resultPtr));
+ *malware = reinterpret_cast<csr_cs_malware_h>(ret.second);
+ } else {
+ *malware = nullptr;
+ }
return ret.first;
@@ -255,10 +260,14 @@ int csr_cs_scan_file(csr_cs_context_h handle, const char *file_path,
hExt->getContext(),
Client::getAbsolutePath(file_path));
- if (ret.second)
- hExt->add(ResultPtr(ret.second));
+ ResultPtr resultPtr(ret.second);
- *malware = reinterpret_cast<csr_cs_malware_h>(ret.second);
+ if (ret.second && !ret.second->malwareName.empty()) {
+ hExt->add(std::move(resultPtr));
+ *malware = reinterpret_cast<csr_cs_malware_h>(ret.second);
+ } else {
+ *malware = nullptr;
+ }
return ret.first;
@@ -278,6 +287,7 @@ int csr_cs_set_file_scanned_cb(csr_cs_context_h handle, csr_cs_file_scanned_cb c
auto hExt = reinterpret_cast<Client::HandleExt *>(handle);
hExt->m_cb.onScanned = callback;
+ hExt->getContext()->set(static_cast<int>(CsContext::Key::ScannedCbRegistered), true);
return CSR_ERROR_NONE;
@@ -391,25 +401,11 @@ int csr_cs_scan_files_async(csr_cs_context_h handle, const char *file_paths[],
EXCEPTION_ASYNC_SAFE_START(hExt->m_cb, user_data)
if (hExt->isStopped())
- ThrowExcInfo(-999, "Async operation cancelled!");
-
- auto ret = hExt->dispatch<std::pair<int, std::shared_ptr<StrSet>>>(
- CommandId::CANONICALIZE_PATHS, *fileSet);
-
- if (ret.first != CSR_ERROR_NONE)
- ThrowExc(ret.first, "Error on getting canonicalized paths in subthread. "
- "ret: " << ret.first);
-
- std::shared_ptr<StrSet> canonicalizedFiles;
-
- if (ret.second == nullptr)
- canonicalizedFiles = std::make_shared<StrSet>();
- else
- canonicalizedFiles = std::move(ret.second);
+ ThrowExcInfo(ASYNC_EVENT_CANCEL, "Async operation cancelled!");
Client::AsyncLogic l(hExt, user_data);
- l.scanFiles(*canonicalizedFiles);
+ l.scanFiles(*fileSet);
EXCEPTION_SAFE_END
});
@@ -427,39 +423,9 @@ API
int csr_cs_scan_dir_async(csr_cs_context_h handle, const char *dir_path,
void *user_data)
{
- EXCEPTION_SAFE_START
-
- if (handle == nullptr)
- return CSR_ERROR_INVALID_HANDLE;
- else if (dir_path == nullptr || dir_path[0] == '\0')
- return CSR_ERROR_INVALID_PARAMETER;
-
- auto hExt = reinterpret_cast<Client::HandleExt *>(handle);
-
- if (hExt->isRunning()) {
- ERROR("Async scanning already running with this handle.");
- return CSR_ERROR_BUSY;
- }
-
- auto dir = std::make_shared<std::string>(Client::getAbsolutePath(dir_path));
-
- auto task = std::make_shared<Task>([hExt, user_data, dir] {
- EXCEPTION_ASYNC_SAFE_START(hExt->m_cb, user_data)
+ const char *dir_paths[1] = { dir_path };
- Client::AsyncLogic l(hExt, user_data);
-
- l.scanDir(*dir);
-
- EXCEPTION_SAFE_END
- });
-
- std::lock_guard<std::mutex> l(hExt->m_dispatchMutex);
-
- hExt->dispatchAsync(task);
-
- return CSR_ERROR_NONE;
-
- EXCEPTION_SAFE_END
+ return ::csr_cs_scan_dirs_async(handle, dir_paths, 1, user_data);
}
API
@@ -493,27 +459,11 @@ int csr_cs_scan_dirs_async(csr_cs_context_h handle, const char *dir_paths[],
EXCEPTION_ASYNC_SAFE_START(hExt->m_cb, user_data)
if (hExt->isStopped())
- ThrowExcInfo(-999, "Async operation cancelled!");
-
- auto ret = hExt->dispatch<std::pair<int, std::shared_ptr<StrSet>>>(
- CommandId::CANONICALIZE_PATHS, *dirSet);
-
- if (ret.first != CSR_ERROR_NONE)
- ThrowExc(ret.first, "Error on getting canonicalized paths in subthread. "
- "ret: " << ret.first);
-
- std::shared_ptr<StrSet> canonicalizedDirs;
-
- if (ret.second == nullptr)
- canonicalizedDirs = std::make_shared<StrSet>();
- else
- canonicalizedDirs = std::move(ret.second);
-
- Client::eraseSubdirectories(*canonicalizedDirs);
+ ThrowExcInfo(ASYNC_EVENT_CANCEL, "Async operation cancelled!");
Client::AsyncLogic l(hExt, user_data);
- l.scanDirs(*canonicalizedDirs);
+ l.scanDirs(*dirSet);
EXCEPTION_SAFE_END
});
@@ -742,10 +692,14 @@ int csr_cs_get_detected_malware(csr_cs_context_h handle, const char *file_path,
auto ret = hExt->dispatch<std::pair<int, CsDetected *>>(
CommandId::GET_DETECTED, Client::getAbsolutePath(file_path));
- if (ret.second)
- hExt->add(ResultPtr(ret.second));
+ ResultPtr resultPtr(ret.second);
- *malware = reinterpret_cast<csr_cs_malware_h>(ret.second);
+ if (ret.second && !ret.second->malwareName.empty()) {
+ hExt->add(std::move(resultPtr));
+ *malware = reinterpret_cast<csr_cs_malware_h>(ret.second);
+ } else {
+ *malware = nullptr;
+ }
return ret.first;
@@ -818,10 +772,14 @@ int csr_cs_get_ignored_malware(csr_cs_context_h handle, const char *file_path,
auto ret = hExt->dispatch<std::pair<int, CsDetected *>>(
CommandId::GET_IGNORED, Client::getAbsolutePath(file_path));
- if (ret.second)
- hExt->add(ResultPtr(ret.second));
+ ResultPtr resultPtr(ret.second);
- *malware = reinterpret_cast<csr_cs_malware_h>(ret.second);
+ if (ret.second && !ret.second->malwareName.empty()) {
+ hExt->add(std::move(resultPtr));
+ *malware = reinterpret_cast<csr_cs_malware_h>(ret.second);
+ } else {
+ *malware = nullptr;
+ }
return ret.first;
diff --git a/src/framework/client/handle.h b/src/framework/client/handle.h
index a398c0a..df2ab15 100644
--- a/src/framework/client/handle.h
+++ b/src/framework/client/handle.h
@@ -43,6 +43,9 @@ public:
template<typename ...Args>
void ping(Args &&...);
+ template<typename Type>
+ Type revent(void);
+
virtual void add(ResultPtr &&);
virtual void add(ResultListPtr &&);
@@ -71,5 +74,11 @@ void Handle::ping(Args &&...args)
this->m_dispatcher->methodPing(std::forward<Args>(args)...);
}
+template<typename Type>
+Type Handle::revent()
+{
+ return this->m_dispatcher->receiveEvent<Type>();
+}
+
} // namespace Client
} // namespace Csr
diff --git a/src/framework/client/utils.cpp b/src/framework/client/utils.cpp
index da69690..98adece 100644
--- a/src/framework/client/utils.cpp
+++ b/src/framework/client/utils.cpp
@@ -25,6 +25,8 @@
#include "common/audit/logger.h"
#include "common/exception.h"
+#include "common/async-protocol.h"
+
#include <csr-error.h>
__attribute__((constructor))
@@ -69,7 +71,7 @@ void exceptionGuardAsync(const Callback &callbacks, void *userdata,
if (callbacks.onCompleted != nullptr)
callbacks.onCompleted(userdata);
} catch (const Exception &e) {
- if (e.error() == -999) {
+ if (e.error() == ASYNC_EVENT_CANCEL) {
INFO("Async operation cancel exception!");
if (callbacks.onCancelled != nullptr)
callbacks.onCancelled(userdata);
diff --git a/src/framework/common/async-protocol.h b/src/framework/common/async-protocol.h
new file mode 100644
index 0000000..da74158
--- /dev/null
+++ b/src/framework/common/async-protocol.h
@@ -0,0 +1,35 @@
+/*
+ * 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 async-protocol.h
+ * @author Kyungwook Tak (k.tak@samsung.com)
+ * @version 1.0
+ * @brief Protocol for asynchronous scanning operations
+ */
+#pragma once
+
+namespace Csr {
+
+// should be positive values not to be conflicted with error code in csr-error.h
+typedef enum {
+ ASYNC_EVENT_START = 0x10, // operation started
+ ASYNC_EVENT_COMPLETE = 0x20, // operation completed
+ ASYNC_EVENT_CANCEL = 0x30, // operation cancelled
+ ASYNC_EVENT_MALWARE_NONE = 0x40, // target scanned and no malware detected
+ ASYNC_EVENT_MALWARE_DETECTED = 0x50, // target scanned and malware detected
+} async_op_protocol_e;
+
+}
diff --git a/src/framework/common/command-id.h b/src/framework/common/command-id.h
index c4b0936..497c2b7 100644
--- a/src/framework/common/command-id.h
+++ b/src/framework/common/command-id.h
@@ -33,9 +33,8 @@ enum class CommandId : int {
GET_DETECTED_LIST = 0x1102,
GET_IGNORED = 0x1103,
GET_IGNORED_LIST = 0x1104,
- GET_SCANNABLE_FILES = 0x1105,
- CANONICALIZE_PATHS = 0x1106,
- SET_DIR_TIMESTAMP = 0x1107,
+ SCAN_DIRS_ASYNC = 0x1105,
+ SCAN_FILES_ASYNC = 0x1106,
CANCEL_OPERATION = 0x1108,
// handle result
JUDGE_STATUS = 0x1201,
diff --git a/src/framework/common/cs-context.cpp b/src/framework/common/cs-context.cpp
index d8ebedd..e744da2 100644
--- a/src/framework/common/cs-context.cpp
+++ b/src/framework/common/cs-context.cpp
@@ -29,7 +29,8 @@ namespace Csr {
CsContext::CsContext() noexcept :
askUser(CSR_CS_ASK_USER_NO),
coreUsage(CSR_CS_CORE_USAGE_DEFAULT),
- isScanOnCloud(false)
+ isScanOnCloud(false),
+ isScannedCbRegistered(false)
{
}
@@ -37,8 +38,9 @@ CsContext::CsContext(IStream &stream)
{
int intAskUser;
int intCoreUsage;
- Deserializer<std::string, int, int, bool>::Deserialize(stream,
- this->popupMessage, intAskUser, intCoreUsage, this->isScanOnCloud);
+ Deserializer<std::string, int, int, bool, bool>::Deserialize(stream,
+ this->popupMessage, intAskUser, intCoreUsage, this->isScanOnCloud,
+ this->isScannedCbRegistered);
this->askUser = static_cast<csr_cs_ask_user_e>(intAskUser);
this->coreUsage = static_cast<csr_cs_core_usage_e>(intCoreUsage);
@@ -46,9 +48,10 @@ CsContext::CsContext(IStream &stream)
void CsContext::Serialize(IStream &stream) const
{
- Serializer<std::string, int, int, bool>::Serialize(stream,
+ Serializer<std::string, int, int, bool, bool>::Serialize(stream,
this->popupMessage, static_cast<int>(this->askUser),
- static_cast<int>(this->coreUsage), this->isScanOnCloud);
+ static_cast<int>(this->coreUsage), this->isScanOnCloud,
+ this->isScannedCbRegistered);
}
void CsContext::set(int key, int value)
@@ -98,6 +101,10 @@ void CsContext::set(int key, bool value)
this->isScanOnCloud = value;
break;
+ case Key::ScannedCbRegistered:
+ this->isScannedCbRegistered = value;
+ break;
+
default:
ThrowExc(CSR_ERROR_SERVER, "Invalid key[" << key << "] comes in to set as bool.");
}
@@ -153,6 +160,10 @@ void CsContext::get(int key, bool &value) const
value = this->isScanOnCloud;
break;
+ case Key::ScannedCbRegistered:
+ value = this->isScannedCbRegistered;
+ break;
+
default:
ThrowExc(CSR_ERROR_SERVER, "Invalid key[" << key << "] comes in to get as bool.");
}
diff --git a/src/framework/common/cs-context.h b/src/framework/common/cs-context.h
index 0161c26..3ef7647 100644
--- a/src/framework/common/cs-context.h
+++ b/src/framework/common/cs-context.h
@@ -43,6 +43,7 @@ struct API CsContext : public IContext {
CoreUsage = 0x11, // int
ScanOnCloud = 0x20, // bool
+ ScannedCbRegistered = 0x21,
};
CsContext() noexcept;
@@ -70,6 +71,7 @@ struct API CsContext : public IContext {
csr_cs_ask_user_e askUser;
csr_cs_core_usage_e coreUsage;
bool isScanOnCloud;
+ bool isScannedCbRegistered;
};
}
diff --git a/src/framework/common/dispatcher.h b/src/framework/common/dispatcher.h
index 9b4f0fb..3b534db 100644
--- a/src/framework/common/dispatcher.h
+++ b/src/framework/common/dispatcher.h
@@ -46,6 +46,9 @@ public:
template<typename ...Args>
void methodPing(Args &&...args);
+ template<typename Type>
+ Type receiveEvent(void);
+
private:
void connect(void);
@@ -78,4 +81,18 @@ void Dispatcher::methodPing(Args &&...args)
this->m_connection->send(BinaryQueue::Serialize(std::forward<Args>(args)...).pop());
}
+template<typename Type>
+Type Dispatcher::receiveEvent()
+{
+ this->connect();
+
+ BinaryQueue q;
+ q.push(this->m_connection->receive());
+
+ Type response;
+ q.Deserialize(response);
+
+ return response;
+}
+
}
diff --git a/src/framework/common/serialization.h b/src/framework/common/serialization.h
index b11baea..6b31678 100644
--- a/src/framework/common/serialization.h
+++ b/src/framework/common/serialization.h
@@ -325,6 +325,15 @@ struct Deserialization {
object.reset(new T(stream));
}
+ template <typename T>
+ static void Deserialize(IStream &stream, std::unique_ptr<T> &object)
+ {
+ if (stream.empty())
+ object.reset();
+ else
+ object.reset(new T(stream));
+ }
+
// char
static void Deserialize(IStream &stream, char &value)
{
@@ -519,6 +528,20 @@ struct Deserialization {
}
}
+ template <typename T, typename R, typename A>
+ static void Deserialize(IStream &stream, std::unique_ptr<std::basic_string<T, R, A>> &str)
+ {
+ if (stream.empty()) {
+ str.reset();
+ } else {
+ int length;
+ stream.read(sizeof(length), &length);
+ std::vector<T> buf(length);
+ stream.read(length * sizeof(T), buf.data());
+ str.reset(new std::basic_string<T, R, A>(buf.data(), buf.data() + length));
+ }
+ }
+
// STL templates
// std::list
@@ -554,6 +577,16 @@ struct Deserialization {
Deserialize(stream, *list);
}
}
+ template <typename T>
+ static void Deserialize(IStream &stream, std::unique_ptr<std::list<T>> &list)
+ {
+ if (stream.empty()) {
+ list.reset();
+ } else {
+ list.reset(new std::list<T>);
+ Deserialize(stream, *list);
+ }
+ }
template <typename T>
static void Deserialize(IStream &stream, std::set<T> &set)
@@ -587,6 +620,16 @@ struct Deserialization {
Deserialize(stream, *set);
}
}
+ template <typename T>
+ static void Deserialize(IStream &stream, std::unique_ptr<std::set<T>> &set)
+ {
+ if (stream.empty()) {
+ set.reset();
+ } else {
+ set.reset(new std::set<T>);
+ Deserialize(stream, *set);
+ }
+ }
// RawBuffer
template <typename A>
@@ -617,6 +660,16 @@ struct Deserialization {
Deserialize(stream, *vec);
}
}
+ template <typename A>
+ static void Deserialize(IStream &stream, std::unique_ptr<std::vector<unsigned char, A>> &vec)
+ {
+ if (stream.empty()) {
+ vec.reset();
+ } else {
+ vec.reset(new std::vector<unsigned char, A>);
+ Deserialize(stream, *vec);
+ }
+ }
// std::vector
template <typename T, typename A>
diff --git a/src/framework/common/socket.cpp b/src/framework/common/socket.cpp
index ceacba8..0b5c499 100644
--- a/src/framework/common/socket.cpp
+++ b/src/framework/common/socket.cpp
@@ -161,11 +161,10 @@ RawBuffer Socket::read(void) const
size_t total = 0;
size_t size = 0;
- DEBUG("Read data from stream on socket fd[" << this->m_fd << "]");
-
auto bytes = ::read(this->m_fd, &size, sizeof(size));
if (bytes < 0)
- ThrowExc(CSR_ERROR_SOCKET, "Socket data size read failed with errno: " << errno);
+ ThrowExc(CSR_ERROR_SOCKET, "Socket data size read failed on fd[" << this->m_fd <<
+ "] with errno: " << errno);
RawBuffer data(size, 0);
auto buf = reinterpret_cast<char *>(data.data());
@@ -199,11 +198,10 @@ void Socket::write(const RawBuffer &data) const
auto buf = reinterpret_cast<const char *>(data.data());
auto size = data.size();
- DEBUG("Write data to stream on socket fd[" << this->m_fd << "]");
-
auto bytes = ::write(this->m_fd, &size, sizeof(size));
if (bytes < 0)
- ThrowExc(CSR_ERROR_SOCKET, "Socket data size write failed with errno: " << errno);
+ ThrowExc(CSR_ERROR_SOCKET, "Socket data size write failed on fd[" << this->m_fd <<
+ "] with errno: " << errno);
while (total < size) {
bytes = ::write(this->m_fd, buf + total, size - total);
diff --git a/src/framework/db/manager.cpp b/src/framework/db/manager.cpp
index 7e036ef..3e70775 100644
--- a/src/framework/db/manager.cpp
+++ b/src/framework/db/manager.cpp
@@ -457,21 +457,20 @@ RowShPtr Manager::getWorstByPkgPath(const std::string &pkgPath, time_t since)
return row;
}
-void Manager::insertDetectedFile(const std::string &filepath, const CsDetected &d,
- const std::string &dataVersion)
+void Manager::insertDetectedFile(const CsDetected &d, const std::string &dataVersion)
{
std::lock_guard<std::mutex> l(this->m_mutex);
- this->insertName(filepath);
- this->insertDetected(d, filepath, dataVersion);
+ this->insertName(d.targetName);
+ this->insertDetected(d, d.targetName, dataVersion);
}
-void Manager::insertDetectedFileInApp(const std::string &pkgpath, const std::string &filepath,
+void Manager::insertDetectedFileInApp(const std::string &filepath,
const CsDetected &d, const std::string &dataVersion)
{
std::lock_guard<std::mutex> l(this->m_mutex);
- this->insertName(pkgpath);
+ this->insertName(d.targetName);
this->insertDetected(d, filepath, dataVersion);
}
diff --git a/src/framework/db/manager.h b/src/framework/db/manager.h
index d63e05b..2b4b38d 100644
--- a/src/framework/db/manager.h
+++ b/src/framework/db/manager.h
@@ -66,9 +66,8 @@ public:
RowShPtrs getDetectedByFilepathOnDir(const std::string &dir, time_t since);
RowShPtr getWorstByPkgPath(const std::string &pkgPath, time_t since);
- void insertDetectedFile(const std::string &filepath, const CsDetected &d,
- const std::string &dataVersion);
- void insertDetectedFileInApp(const std::string &pkgpath, const std::string &filepath,
+ void insertDetectedFile(const CsDetected &d, const std::string &dataVersion);
+ void insertDetectedFileInApp(const std::string &filepath,
const CsDetected &d, const std::string &dataVersion);
void insertDetectedAppByCloud(const std::string &name, const std::string &pkgId,
const CsDetected &d, const std::string &dataVersion);
diff --git a/src/framework/service/cs-logic.cpp b/src/framework/service/cs-logic.cpp
index 6dd4699..6218478 100644
--- a/src/framework/service/cs-logic.cpp
+++ b/src/framework/service/cs-logic.cpp
@@ -22,6 +22,7 @@
#include "service/cs-logic.h"
#include <utility>
+#include <cstdlib>
#include <climits>
#include <cerrno>
#include <unistd.h>
@@ -30,6 +31,7 @@
#include "common/audit/logger.h"
#include "common/exception.h"
+#include "common/async-protocol.h"
#include "service/type-converter.h"
#include "service/core-usage.h"
#include "service/dir-blacklist.h"
@@ -132,7 +134,7 @@ FilePtr canonicalizePathWithFile(const std::string &path)
{
auto resolved = resolvePath(path);
- auto fileptr = File::create(path, nullptr);
+ auto fileptr = File::create(resolved, nullptr);
if (!isReadable(fileptr->getName()))
ThrowExcWarn(CSR_ERROR_FILE_DO_NOT_EXIST, "File is not readable: " << fileptr->getName());
@@ -140,6 +142,33 @@ FilePtr canonicalizePathWithFile(const std::string &path)
return fileptr;
}
+void eraseSubdirectories(StrSet &dirset)
+{
+ if (dirset.size() < 2)
+ return;
+
+ for (auto it = dirset.begin(); it != dirset.end(); ++it) {
+ auto itsub = it;
+ ++itsub;
+ while (true) {
+ if (itsub == dirset.end())
+ break;
+
+ auto itl = it->length();
+ auto itsubl = itsub->length();
+
+ if (itl + 1 >= itsubl || // to short to be sub-directory
+ itsub->compare(0, itl, *it) != 0 || // prefix isn't matched
+ (*it != "/" && itsub->at(itl) != '/')) { // has '/' at the end of prefix
+ ++itsub;
+ continue;
+ }
+
+ itsub = dirset.erase(itsub);
+ }
+ }
+}
+
} // namespace anonymous
CsLogic::CsLogic(const std::shared_ptr<CsLoader> &loader,
@@ -176,15 +205,17 @@ RawBuffer CsLogic::scanData(const CsContext &context, const RawBuffer &data)
if (result == nullptr)
return BinaryQueue::Serialize(CSR_ERROR_NONE).pop();
- auto d = this->convert(result, std::string(), timestamp);
+ auto malware = this->convert(result, std::string(), timestamp);
- return this->handleAskUser(context, d);
+ return BinaryQueue::Serialize(this->handleAskUser(context, *malware), malware).pop();
}
-RawBuffer CsLogic::scanAppOnCloud(const CsContext &context,
- const std::string &pkgPath,
- const std::string &pkgId)
+int CsLogic::scanAppOnCloud(const CsContext &context, const FilePtr &pkgPtr,
+ CsDetectedPtr &malware)
{
+ const auto &pkgPath = pkgPtr->getName();
+ const auto &pkgId = pkgPtr->getAppPkgId();
+
CsEngineContext engineContext(this->m_loader);
auto &c = engineContext.get();
@@ -194,20 +225,22 @@ RawBuffer CsLogic::scanAppOnCloud(const CsContext &context,
this->m_loader->scanAppOnCloud(c, pkgPath, &result);
if (!result)
- return BinaryQueue::Serialize(CSR_ERROR_NONE).pop();
+ return CSR_ERROR_NONE;
- auto detected = this->convert(result, pkgPath, timestamp);
- detected.isApp = true;
- detected.pkgId = pkgId;
+ malware = this->convert(result, pkgPath, timestamp);
+ malware->isApp = true;
+ malware->pkgId = pkgId;
- this->m_db->insertDetectedAppByCloud(pkgPath, pkgId, detected, this->m_dataVersion);
+ this->m_db->insertDetectedAppByCloud(pkgPath, pkgId, *malware, this->m_dataVersion);
- return this->handleAskUser(context, detected);
+ return this->handleAskUser(context, *malware, pkgPtr);
}
-CsDetectedPtr CsLogic::scanAppDelta(const std::string &pkgPath, const std::string &pkgId,
- std::string &riskiestPath)
+CsDetectedPtr CsLogic::scanAppDelta(const FilePtr &pkgPtr, std::string &riskiestPath)
{
+ const auto &pkgPath = pkgPtr->getName();
+ const auto &pkgId = pkgPtr->getAppPkgId();
+
auto starttime = ::time(nullptr);
CsEngineContext engineContext(this->m_loader);
@@ -236,17 +269,13 @@ CsDetectedPtr CsLogic::scanAppDelta(const std::string &pkgPath, const std::strin
INFO("New malware detected on file: " << file->getPath());
auto candidate = this->convert(result, pkgPath, timestamp);
- candidate.isApp = true;
- candidate.pkgId = pkgId;
+ candidate->isApp = true;
+ candidate->pkgId = pkgId;
- this->m_db->insertDetectedFileInApp(pkgPath, file->getPath(), candidate,
- this->m_dataVersion);
+ this->m_db->insertDetectedFileInApp(file->getPath(), *candidate, this->m_dataVersion);
- if (!riskiest) {
- riskiest.reset(new CsDetected(std::move(candidate)));
- riskiestPath = file->getPath();
- } else if (*riskiest < candidate) {
- *riskiest = std::move(candidate);
+ if (riskiest == nullptr || *riskiest < *candidate) {
+ riskiest = std::move(candidate);
riskiestPath = file->getPath();
}
}, pkgPath, false, lastScanTime);
@@ -258,13 +287,14 @@ CsDetectedPtr CsLogic::scanAppDelta(const std::string &pkgPath, const std::strin
return riskiest;
}
-RawBuffer CsLogic::scanApp(const CsContext &context, const FilePtr &pkgPtr)
+int CsLogic::scanApp(const CsContext &context, const FilePtr &pkgPtr,
+ CsDetectedPtr &malware)
{
const auto &pkgPath = pkgPtr->getName();
const auto &pkgId = pkgPtr->getAppPkgId();
if (context.isScanOnCloud && this->m_loader->scanAppOnCloudSupported())
- return this->scanAppOnCloud(context, pkgPath, pkgId);
+ return this->scanAppOnCloud(context, pkgPtr, malware);
CsEngineContext engineContext(this->m_loader);
auto since = this->m_loader->getEngineLatestUpdateTime(engineContext.get());
@@ -273,7 +303,7 @@ RawBuffer CsLogic::scanApp(const CsContext &context, const FilePtr &pkgPtr)
auto history = this->m_db->getWorstByPkgPath(pkgPath, since);
// riskiest detected among newly scanned files
std::string riskiestPath;
- auto riskiest = this->scanAppDelta(pkgPath, pkgId, riskiestPath);
+ auto riskiest = this->scanAppDelta(pkgPtr, riskiestPath);
// history after delta scan. if worst file is changed, it's rescanned in scanAppDelta
// and deleted from db if it's cured. if history != nullptr && after == nullptr,
// it means worst detected item is cured anyway.
@@ -287,21 +317,27 @@ RawBuffer CsLogic::scanApp(const CsContext &context, const FilePtr &pkgPtr)
this->m_db->insertWorst(pkgId, pkgPath, riskiestPath);
- return this->handleAskUser(context, *riskiest);
+ malware.reset(new CsDetected());
+ *malware = std::move(*riskiest);
+ return this->handleAskUser(context, *malware);
} else {
INFO("worst case is remained and can be re-used on pkg[" << pkgPath << "]");
if (history->isIgnored)
- return BinaryQueue::Serialize(CSR_ERROR_NONE).pop();
+ return CSR_ERROR_NONE;
- return this->handleAskUser(context, *history);
+ malware.reset(new CsDetected());
+ *malware = std::move(*history);
+ return this->handleAskUser(context, *malware);
}
} else if (history && after && !riskiest) {
INFO("worst case is remained and NO new detected. history can be re-used. "
"on pkg[" << pkgPath << "]");
if (history->isIgnored)
- return BinaryQueue::Serialize(CSR_ERROR_NONE).pop();
+ return CSR_ERROR_NONE;
- return this->handleAskUser(context, *history);
+ malware.reset(new CsDetected());
+ *malware = std::move(*history);
+ return this->handleAskUser(context, *malware);
} else if (history && !after && riskiest) {
INFO("worst case is deleted but new detected. we have to find out "
"worse case in db and compare it with riskiest first. on pkg[" << pkgPath <<
@@ -315,7 +351,7 @@ RawBuffer CsLogic::scanApp(const CsContext &context, const FilePtr &pkgPtr)
if (!worse) {
INFO("No detected malware found in db.... Newly detected malware is removed by "
"other client. Handle it as fully clean case.");
- return BinaryQueue::Serialize(CSR_ERROR_NONE).pop();
+ return CSR_ERROR_NONE;
}
if (*riskiest < *worse) {
@@ -332,16 +368,20 @@ RawBuffer CsLogic::scanApp(const CsContext &context, const FilePtr &pkgPtr)
this->m_db->insertWorst(pkgId, pkgPath, riskiestPath);
- return this->handleAskUser(context, *riskiest);
+ malware.reset(new CsDetected());
+ *malware = std::move(*riskiest);
+ return this->handleAskUser(context, *malware);
} else {
INFO("worst case is deleted but same or less level newly detected. on pkg[" <<
pkgPath << "]");
this->m_db->insertWorst(pkgId, pkgPath, riskiestPath);
if (history->isIgnored)
- return BinaryQueue::Serialize(CSR_ERROR_NONE).pop();
+ return CSR_ERROR_NONE;
- return this->handleAskUser(context, *riskiest);
+ malware.reset(new CsDetected());
+ *malware = std::move(*riskiest);
+ return this->handleAskUser(context, *malware);
}
} else if (history && !after && !riskiest) {
since = this->m_loader->getEngineLatestUpdateTime(engineContext.get());
@@ -359,9 +399,11 @@ RawBuffer CsLogic::scanApp(const CsContext &context, const FilePtr &pkgPtr)
this->m_db->insertWorst(pkgId, pkgPath, worse->fileInAppPath);
if (worse->isIgnored)
- return BinaryQueue::Serialize(CSR_ERROR_NONE).pop();
+ return CSR_ERROR_NONE;
- return this->handleAskUser(context, *worse);
+ malware.reset(new CsDetected());
+ *malware = std::move(*worse);
+ return this->handleAskUser(context, *malware);
}
}
@@ -369,29 +411,25 @@ RawBuffer CsLogic::scanApp(const CsContext &context, const FilePtr &pkgPtr)
"NO worse case. the pkg[" << pkgPath << "] is clean.");
this->m_db->deleteDetectedByNameOnPath(pkgPath);
- return BinaryQueue::Serialize(CSR_ERROR_NONE).pop();
+ return CSR_ERROR_NONE;
} else if (!history && riskiest) {
INFO("no history and new detected");
this->m_db->insertWorst(pkgId, pkgPath, riskiestPath);
- return this->handleAskUser(context, *riskiest);
+ malware.reset(new CsDetected());
+ *malware = std::move(*riskiest);
+ return this->handleAskUser(context, *malware);
} else {
DEBUG("no history and no new detected");
- return BinaryQueue::Serialize(CSR_ERROR_NONE).pop();
+ return CSR_ERROR_NONE;
}
}
-RawBuffer CsLogic::scanFile(const CsContext &context, const std::string &filepath)
+int CsLogic::scanFileInternal(const CsContext &context, const FilePtr &target,
+ CsDetectedPtr &malware)
{
- if (this->m_db->getEngineState(CSR_ENGINE_CS) != CSR_STATE_ENABLE)
- ThrowExc(CSR_ERROR_ENGINE_DISABLED, "engine is disabled");
-
- setCoreUsage(context.coreUsage);
-
- auto target = canonicalizePathWithFile(filepath);
-
if (target->isInApp())
- return this->scanApp(context, target);
+ return this->scanApp(context, target, malware);
const auto &name = target->getName();
@@ -401,7 +439,7 @@ RawBuffer CsLogic::scanFile(const CsContext &context, const std::string &filepat
DEBUG("Scan request on file: " << name);
if (isInBlackList(name))
- return BinaryQueue::Serialize(CSR_ERROR_NONE).pop();
+ return CSR_ERROR_NONE;
CsEngineContext engineContext(this->m_loader);
auto &c = engineContext.get();
@@ -413,84 +451,184 @@ RawBuffer CsLogic::scanFile(const CsContext &context, const std::string &filepat
// detected handle is null if it's safe
if (result == nullptr)
- return BinaryQueue::Serialize(CSR_ERROR_NONE).pop();
+ return CSR_ERROR_NONE;
INFO("Malware detected on file: " << name);
- auto d = this->convert(result, name, timestamp);
+ malware = this->convert(result, name, timestamp);
// check malware detected history for inherit ignored flag
auto since = this->m_loader->getEngineLatestUpdateTime(c);
auto history = this->m_db->getDetectedAllByNameOnPath(name, since);
- this->m_db->insertDetectedFile(d.targetName, d, this->m_dataVersion);
+ this->m_db->insertDetectedFile(*malware, this->m_dataVersion);
- if (history != nullptr && history->isIgnored && !(d > *history))
- return BinaryQueue::Serialize(CSR_ERROR_NONE).pop();
- else
- return this->handleAskUser(context, d, std::move(target));
+ if (history != nullptr && history->isIgnored && !(*malware > *history)) {
+ INFO("Ignore malware on file: " << name);
+ malware.reset();
+ return CSR_ERROR_NONE;
+ } else {
+ return this->handleAskUser(context, *malware, target);
+ }
}
-// Application in input param directory will be treated as one item.
-// Application base directory path is inserted to file set.
-// e.g., input param dir : "/opt/usr" (applications in "/opt/usr/apps")
-// ls /opt/usr/ :
-// /opt/usr/file-not-in-app1
-// /opt/usr/file-not-in-app2
-// /opt/usr/apps/org.tizen.tutorial
-// /opt/usr/apps/org.tizen.tutorial/file-in-app1
-// /opt/usr/apps/org.tizen.tutorial/file-in-app2
-// /opt/usr/apps/org.tizen.message/file-in-app1
-// /opt/usr/apps/org.tizen.message/file-in-app2
-// /opt/usr/apps/org.tizen.flash/file-in-app1
-// /opt/usr/apps/org.tizen.flash/file-in-app2
-//
-// and detected history exist on...
-// /opt/usr/apps/org.tizen.message/file-in-app2
-// /opt/usr/apps/org.tizen.flash (If target name is app base directory path,
-// it's detected by scan on cloud)
-//
-// output scannable file set will be:
-// 1) /opt/usr/file-not-in-app1
-// 2) /opt/usr/file-not-in-app2
-// 3) /opt/usr/apps/org.tizen.tutorial (app base directory path)
-// 4) /opt/usr/apps/org.tizen.message (app base directory path)
-// 5) /opt/usr/apps/org.tizen.flash (app base directory path)
-// % items which has detected history is included in list as well.
-RawBuffer CsLogic::getScannableFiles(const std::string &dir, const std::function<void()> &isCancelled)
+RawBuffer CsLogic::scanFile(const CsContext &context, const std::string &filepath)
{
if (this->m_db->getEngineState(CSR_ENGINE_CS) != CSR_STATE_ENABLE)
ThrowExc(CSR_ERROR_ENGINE_DISABLED, "engine is disabled");
- auto targetdir = canonicalizePath(dir, true);
+ setCoreUsage(context.coreUsage);
- CsEngineContext csEngineContext(this->m_loader);
- auto since = this->m_loader->getEngineLatestUpdateTime(csEngineContext.get());
+ CsDetectedPtr malware;
+ auto ret = this->scanFileInternal(context, canonicalizePathWithFile(filepath), malware);
+ if (malware != nullptr)
+ return BinaryQueue::Serialize(ret, malware).pop();
+ else
+ return BinaryQueue::Serialize(ret).pop();
+}
- auto lastScanTime = this->m_db->getLastScanTime(targetdir, since);
+RawBuffer CsLogic::scanFilesAsync(const ConnShPtr &conn, const CsContext &context,
+ StrSet &paths, const std::function<void()> &isCancelled)
+{
+ if (this->m_db->getEngineState(CSR_ENGINE_CS) != CSR_STATE_ENABLE)
+ ThrowExc(CSR_ERROR_ENGINE_DISABLED, "engine is disabled");
- StrSet fileset;
+ conn->send(BinaryQueue::Serialize(ASYNC_EVENT_START).pop());
- auto visitor = FsVisitor::create([&](const FilePtr &file) {
+ StrSet canonicalized;
+
+ for (const auto &path : paths) {
isCancelled();
- DEBUG("Scannable item: " << file->getName());
- fileset.insert(file->getName());
- }, targetdir, true, lastScanTime);
+ FilePtr target;
+ try {
+ target = canonicalizePathWithFile(path);
- visitor->run();
+ if (canonicalized.find(target->getName()) != canonicalized.end())
+ continue;
+
+ INFO("Insert to canonicalized list: " << target->getName());
+ canonicalized.insert(target->getName());
+ } catch (const Exception &e) {
+ if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST ||
+ e.error() == CSR_ERROR_FILE_SYSTEM) {
+ WARN("File-system related exception occured while getting "
+ "canonicalize path of path: " << path << " " << e.what() <<
+ ". Ignore this exception.");
+ continue;
+ } else {
+ ERROR("Non-file-system related exception occured while getting "
+ "canonicalize path of path: " << path << " " << e.what());
+ throw;
+ }
+ }
- isCancelled();
+ CsDetectedPtr malware;
+ auto retcode = this->scanFileInternal(context, target, malware);
+
+ switch (retcode) {
+ case CSR_ERROR_NONE:
+ case CSR_ERROR_FILE_DO_NOT_EXIST:
+ case CSR_ERROR_FILE_CHANGED:
+ case CSR_ERROR_FILE_SYSTEM:
+ if (malware != nullptr) {
+ conn->send(BinaryQueue::Serialize(ASYNC_EVENT_MALWARE_DETECTED).pop());
+ conn->send(BinaryQueue::Serialize(malware).pop());
+ } else if (context.isScannedCbRegistered) {
+ conn->send(BinaryQueue::Serialize(ASYNC_EVENT_MALWARE_NONE).pop());
+ conn->send(BinaryQueue::Serialize(target->getName()).pop());
+ }
+
+ break;
- if (lastScanTime != -1) {
- // for case: scan history exist and not modified.
- for (auto &row : this->m_db->getDetectedAllByNameOnDir(targetdir, since)) {
+ default:
+ ThrowExc(retcode, "Error on async scanning: " << retcode);
+ }
+ }
+
+ return BinaryQueue::Serialize(ASYNC_EVENT_COMPLETE).pop();
+}
+
+RawBuffer CsLogic::scanDirsAsync(const ConnShPtr &conn, const CsContext &context,
+ StrSet &paths, const std::function<void()> &isCancelled)
+{
+ if (this->m_db->getEngineState(CSR_ENGINE_CS) != CSR_STATE_ENABLE)
+ ThrowExc(CSR_ERROR_ENGINE_DISABLED, "engine is disabled");
+
+ StrSet dirs;
+
+ for (const auto &path : paths) {
+ try {
+ auto target = canonicalizePath(File::getPkgPath(path), true);
+
+ if (dirs.find(target) == dirs.end()) {
+ INFO("Insert to canonicalized list: " << target);
+ dirs.emplace(std::move(target));
+ }
+ } catch (const Exception &e) {
+ if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST ||
+ e.error() == CSR_ERROR_FILE_SYSTEM) {
+ WARN("File-system related exception occured while getting "
+ "canonicalize path of path: " << path << " " << e.what() <<
+ ". Ignore this exception.");
+ continue;
+ } else {
+ ERROR("Non-file-system related exception occured while getting "
+ "canonicalize path of path: " << path << " " << e.what());
+ throw;
+ }
+ }
+ }
+
+ eraseSubdirectories(dirs);
+
+ DEBUG("send error none to client before starting scanning");
+
+ conn->send(BinaryQueue::Serialize(ASYNC_EVENT_START).pop());
+
+ CsEngineContext engineContext(this->m_loader);
+ auto t = this->m_loader->getEngineLatestUpdateTime(engineContext.get());
+
+ DEBUG("Start async scanning!!!!!");
+
+ StrSet malwareList;
+ for (const auto &dir : dirs) {
+ isCancelled();
+
+ DEBUG("Start async scanning for dir: " << dir);
+
+ for (auto &row : this->m_db->getDetectedAllByNameOnDir(dir, t)) {
isCancelled();
try {
auto fileptr = File::create(row->targetName, nullptr);
- fileset.insert(fileptr->getName());
+ CsDetectedPtr malware;
+ auto retcode = this->scanFileInternal(context, fileptr, malware);
+
+ switch (retcode) {
+ case CSR_ERROR_NONE:
+ case CSR_ERROR_FILE_DO_NOT_EXIST:
+ case CSR_ERROR_FILE_CHANGED:
+ case CSR_ERROR_FILE_SYSTEM:
+ if (malware != nullptr) {
+ conn->send(BinaryQueue::Serialize(ASYNC_EVENT_MALWARE_DETECTED).pop());
+ conn->send(BinaryQueue::Serialize(malware).pop());
+ malwareList.insert(row->targetName);
+ } else if (context.isScannedCbRegistered) {
+ conn->send(BinaryQueue::Serialize(ASYNC_EVENT_MALWARE_NONE).pop());
+ conn->send(BinaryQueue::Serialize(row->targetName).pop());
+ this->m_db->deleteDetectedByNameOnPath(row->targetName);
+ }
+
+ break;
+
+ default:
+ ERROR("Error on rescanning detected malwares in db: " << retcode <<
+ " file: " << fileptr->getName());
+ this->m_db->deleteDetectedByNameOnPath(row->targetName);
+ return BinaryQueue::Serialize(retcode).pop();
+ }
} catch (const Exception &e) {
if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST ||
e.error() == CSR_ERROR_FILE_SYSTEM)
@@ -499,35 +637,55 @@ RawBuffer CsLogic::getScannableFiles(const std::string &dir, const std::function
throw;
}
}
- }
- return BinaryQueue::Serialize(CSR_ERROR_NONE, fileset).pop();
-}
+ auto startTime = ::time(nullptr);
+ auto lastScanTime = this->m_db->getLastScanTime(dir, t);
+ auto visitor = FsVisitor::create([&](const FilePtr &file) {
+ isCancelled();
-RawBuffer CsLogic::canonicalizePaths(const StrSet &paths)
-{
- if (this->m_db->getEngineState(CSR_ENGINE_CS) != CSR_STATE_ENABLE)
- ThrowExc(CSR_ERROR_ENGINE_DISABLED, "engine is disabled");
+ CsDetectedPtr malware;
+ auto retcode = this->scanFileInternal(context, file, malware);
+
+ DEBUG("scanFileInternal done. file: " << file->getName() <<
+ " retcode: " << retcode);
+
+ switch (retcode) {
+ case CSR_ERROR_NONE:
+ case CSR_ERROR_FILE_DO_NOT_EXIST:
+ case CSR_ERROR_FILE_CHANGED:
+ case CSR_ERROR_FILE_SYSTEM:
+ if (malware != nullptr) {
+ auto it = malwareList.find(file->getName());
+ if (it != malwareList.end()) {
+ malwareList.erase(it);
+ break;
+ }
+
+ DEBUG("Malware detected!!!");
+ conn->send(BinaryQueue::Serialize(ASYNC_EVENT_MALWARE_DETECTED).pop());
+ conn->send(BinaryQueue::Serialize(malware).pop());
+ } else if (context.isScannedCbRegistered) {
+ DEBUG("File scanned!!!");
+ conn->send(BinaryQueue::Serialize(ASYNC_EVENT_MALWARE_NONE).pop());
+ conn->send(BinaryQueue::Serialize(file->getName()).pop());
+ }
+
+ break;
+
+ default:
+ ThrowExc(retcode, "Error on async scanning: " << retcode);
+ }
+ }, dir, true, lastScanTime);
- StrSet canonicalized;
+ visitor->run();
- for (const auto &path : paths) {
- auto target = canonicalizePath(path, true);
+ this->m_db->insertLastScanTime(dir, this->m_dataVersion, startTime);
- if (canonicalized.find(target) == canonicalized.end()) {
- INFO("Insert to canonicalized list: " << target);
- canonicalized.emplace(std::move(target));
- }
+ if (lastScanTime == -1)
+ continue;
}
- return BinaryQueue::Serialize(CSR_ERROR_NONE, canonicalized).pop();
-}
-
-RawBuffer CsLogic::setDirTimestamp(const std::string &dir, time_t ts)
-{
- this->m_db->insertLastScanTime(dir, this->m_dataVersion, ts);
-
- return BinaryQueue::Serialize(CSR_ERROR_NONE).pop();
+ return BinaryQueue::Serialize(ASYNC_EVENT_COMPLETE).pop();
}
RawBuffer CsLogic::judgeStatus(const std::string &filepath, csr_cs_action_e action)
@@ -686,11 +844,11 @@ RawBuffer CsLogic::getIgnoredList(const StrSet &_dirSet)
return BinaryQueue::Serialize(CSR_ERROR_NONE, rows).pop();
}
-RawBuffer CsLogic::handleAskUser(const CsContext &c, CsDetected &d, FilePtr &&fileptr)
+int CsLogic::handleAskUser(const CsContext &c, CsDetected &d, const FilePtr &fileptr)
{
if (c.askUser == CSR_CS_ASK_USER_NO) {
d.response = CSR_CS_USER_RESPONSE_USER_NOT_ASKED;
- return BinaryQueue::Serialize(CSR_ERROR_NONE, d).pop();
+ return CSR_ERROR_NONE;
}
Ui::CommandId cid;
@@ -725,57 +883,53 @@ RawBuffer CsLogic::handleAskUser(const CsContext &c, CsDetected &d, FilePtr &&fi
auto r = askUser.cs(cid, c.popupMessage, d);
if (r == -1) {
ERROR("Failed to get user response by popup service for target: " << d.targetName);
- return BinaryQueue::Serialize(CSR_ERROR_USER_RESPONSE_FAILED, d).pop();
+ return CSR_ERROR_USER_RESPONSE_FAILED;
}
d.response = r;
- if (d.response == CSR_CS_USER_RESPONSE_REMOVE && !d.targetName.empty()) {
- try {
- FilePtr _fileptr;
- if (fileptr)
- _fileptr = std::move(fileptr);
- else
- _fileptr = File::create(d.targetName, nullptr);
+ if (d.response != CSR_CS_USER_RESPONSE_REMOVE || d.targetName.empty())
+ return CSR_ERROR_NONE;
- _fileptr->remove();
- } catch (const Exception &e) {
- if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST)
- WARN("File already removed.: " << d.targetName);
- else if (e.error() == CSR_ERROR_FILE_SYSTEM)
- WARN("File type is changed, considered as different file: " <<
- d.targetName);
- else if (e.error() == CSR_ERROR_REMOVE_FAILED)
- return BinaryQueue::Serialize(CSR_ERROR_REMOVE_FAILED, d).pop();
- else
- throw;
- }
-
- this->m_db->deleteDetectedByNameOnPath(d.targetName);
+ try {
+ if (fileptr != nullptr)
+ fileptr->remove();
+ else
+ File::create(d.targetName, nullptr)->remove();
+ } catch (const Exception &e) {
+ if (e.error() == CSR_ERROR_FILE_DO_NOT_EXIST)
+ WARN("File already removed.: " << d.targetName);
+ else if (e.error() == CSR_ERROR_FILE_SYSTEM)
+ WARN("File type is changed, considered as different file: " << d.targetName);
+ else if (e.error() == CSR_ERROR_REMOVE_FAILED)
+ return CSR_ERROR_REMOVE_FAILED;
+ else
+ throw;
}
- return BinaryQueue::Serialize(CSR_ERROR_NONE, d).pop();
+ this->m_db->deleteDetectedByNameOnPath(d.targetName);
+ return CSR_ERROR_NONE;
}
-CsDetected CsLogic::convert(csre_cs_detected_h &result, const std::string &targetName,
+CsDetectedPtr CsLogic::convert(csre_cs_detected_h &result, const std::string &targetName,
time_t timestamp)
{
DEBUG("convert engine result handle to CsDetected start");
- CsDetected d;
+ CsDetectedPtr malware(new CsDetected());
- d.targetName = targetName;
+ malware->targetName = targetName;
csre_cs_severity_level_e eseverity = CSRE_CS_SEVERITY_LOW;
this->m_loader->getSeverity(result, &eseverity);
- this->m_loader->getMalwareName(result, d.malwareName);
- this->m_loader->getDetailedUrl(result, d.detailedUrl);
+ this->m_loader->getMalwareName(result, malware->malwareName);
+ this->m_loader->getDetailedUrl(result, malware->detailedUrl);
- d.ts = timestamp;
- d.severity = Csr::convert(eseverity);
+ malware->ts = timestamp;
+ malware->severity = Csr::convert(eseverity);
- return d;
+ return malware;
}
}
diff --git a/src/framework/service/cs-logic.h b/src/framework/service/cs-logic.h
index 237c67a..3399fbc 100644
--- a/src/framework/service/cs-logic.h
+++ b/src/framework/service/cs-logic.h
@@ -46,9 +46,10 @@ public:
RawBuffer scanData(const CsContext &context, const RawBuffer &data);
RawBuffer scanFile(const CsContext &context, const std::string &filepath);
- RawBuffer getScannableFiles(const std::string &dir, const std::function<void()> &isCancelled);
- RawBuffer canonicalizePaths(const StrSet &paths);
- RawBuffer setDirTimestamp(const std::string &dir, time_t ts);
+ RawBuffer scanFilesAsync(const ConnShPtr &conn, const CsContext &context,
+ StrSet &paths, const std::function<void()> &isCancelled);
+ RawBuffer scanDirsAsync(const ConnShPtr &conn, const CsContext &context,
+ StrSet &paths, const std::function<void()> &isCancelled);
RawBuffer judgeStatus(const std::string &filepath, csr_cs_action_e action);
RawBuffer getDetected(const std::string &filepath);
RawBuffer getDetectedList(const StrSet &dirSet);
@@ -56,16 +57,14 @@ public:
RawBuffer getIgnoredList(const StrSet &dirSet);
private:
- RawBuffer scanApp(const CsContext &context, const FilePtr &pkgPtr);
- RawBuffer scanAppOnCloud(const CsContext &context, const std::string &pkgPath,
- const std::string &pkgId);
- CsDetectedPtr scanAppDelta(const std::string &pkgPath, const std::string &pkgId,
- std::string &riskiestPath);
+ int scanFileInternal(const CsContext &context, const FilePtr &target, CsDetectedPtr &malware);
+ int scanApp(const CsContext &context, const FilePtr &pkgPtr, CsDetectedPtr &malware);
+ int scanAppOnCloud(const CsContext &context, const FilePtr &pkgPtr, CsDetectedPtr &malware);
+ CsDetectedPtr scanAppDelta(const FilePtr &pkgPtr, std::string &riskiestPath);
- CsDetected convert(csre_cs_detected_h &result, const std::string &targetName,
+ CsDetectedPtr convert(csre_cs_detected_h &result, const std::string &targetName,
time_t timestamp);
- RawBuffer handleAskUser(const CsContext &c, CsDetected &d,
- FilePtr &&fileptr = nullptr);
+ int handleAskUser(const CsContext &c, CsDetected &d, const FilePtr &fileptr = nullptr);
std::shared_ptr<CsLoader> m_loader;
std::shared_ptr<Db::Manager> m_db;
diff --git a/src/framework/service/file-system.cpp b/src/framework/service/file-system.cpp
index 214761d..80aa760 100644
--- a/src/framework/service/file-system.cpp
+++ b/src/framework/service/file-system.cpp
@@ -341,7 +341,10 @@ void FsVisitor::run()
INFO("Visiting files start from dir: " << this->m_path);
- this->run(dirptr, currentdir);
+ if (this->m_isBasedOnName && currentdir->isInApp())
+ this->m_targetHandler(currentdir);
+ else
+ this->run(dirptr, currentdir);
}
} // namespace Csr
diff --git a/src/framework/service/server-service.cpp b/src/framework/service/server-service.cpp
index 1ade03a..38bd875 100644
--- a/src/framework/service/server-service.cpp
+++ b/src/framework/service/server-service.cpp
@@ -33,6 +33,7 @@
#include "common/cs-detected.h"
#include "common/wp-result.h"
#include "common/exception.h"
+#include "common/async-protocol.h"
#include "service/exception.h"
#include "service/access-control.h"
#include "service/core-usage.h"
@@ -53,9 +54,8 @@ std::string cidToString(const CommandId &cid)
CID_TOSTRING(GET_DETECTED_LIST);
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(SCAN_DIRS_ASYNC);
+ CID_TOSTRING(SCAN_FILES_ASYNC);
CID_TOSTRING(CANCEL_OPERATION);
CID_TOSTRING(JUDGE_STATUS);
@@ -82,7 +82,7 @@ inline CommandId extractCommandId(BinaryQueue &q)
return id;
}
-}
+} // namespace anonymous
ServerService::ServerService() : Service(), m_workqueue(5)
{
@@ -155,18 +155,19 @@ RawBuffer ServerService::processCs(const ConnShPtr &conn, RawBuffer &data)
return this->m_cslogic->scanFile(*cptr, filepath);
}
- case CommandId::GET_SCANNABLE_FILES: {
+ case CommandId::SCAN_FILES_ASYNC: {
hasPermission(conn);
- std::string dir;
- q.Deserialize(dir);
+ CsContextShPtr cptr;
+ StrSet paths;
+ q.Deserialize(cptr, paths);
auto fd = conn->getFd();
{
std::lock_guard<std::mutex> l(this->m_cancelledMutex);
this->m_isCancelled[fd] = false;
- INFO("Turn off cancelled flag before scannable files start on fd: " << fd);
+ INFO("Turn off cancelled flag before start async. fd: " << fd);
}
Closer closer([this, fd]() {
@@ -175,57 +176,52 @@ RawBuffer ServerService::processCs(const ConnShPtr &conn, RawBuffer &data)
INFO("Erase cancelled flag in closer on fd: " << fd);
});
- return this->m_cslogic->getScannableFiles(dir, [this, fd]() {
+ return this->m_cslogic->scanFilesAsync(conn, *cptr, paths, [this, fd]() {
std::lock_guard<std::mutex> l(this->m_cancelledMutex);
if (this->m_isCancelled.count(fd) == 1 && this->m_isCancelled[fd])
- ThrowExcInfo(-999, "operation cancelled on fd: " << fd);
+ ThrowExcInfo(ASYNC_EVENT_CANCEL, "operation cancelled on fd: " << fd);
});
}
- case CommandId::CANCEL_OPERATION: {
- std::lock_guard<std::mutex> l(this->m_cancelledMutex);
- auto fd = conn->getFd();
- if (this->m_isCancelled.count(fd) == 1) {
- this->m_isCancelled[fd] = true;
- INFO("Trun on cancelled flag of fd: " << fd);
- } else {
- WARN("Nothing to cancel on getting scannable list! fd: " << fd);
- }
-
- return RawBuffer();
- }
-
- case CommandId::CANONICALIZE_PATHS: {
+ case CommandId::SCAN_DIRS_ASYNC: {
hasPermission(conn);
+ CsContextShPtr cptr;
StrSet paths;
- q.Deserialize(paths);
+ q.Deserialize(cptr, paths);
auto fd = conn->getFd();
{
std::lock_guard<std::mutex> l(this->m_cancelledMutex);
this->m_isCancelled[fd] = false;
- INFO("Turn off cancelled flag before canonicalize paths start on fd: " << fd);
+ INFO("Turn off cancelled flag before start async. fd: " << fd);
}
Closer closer([this, fd]() {
std::lock_guard<std::mutex> l(this->m_cancelledMutex);
this->m_isCancelled.erase(fd);
- INFO("Erase cancelled flag in closer of canonicalize paths on fd: " << fd);
+ INFO("Erase cancelled flag in closer on fd: " << fd);
});
- return this->m_cslogic->canonicalizePaths(paths);
+ return this->m_cslogic->scanDirsAsync(conn, *cptr, paths, [this, fd]() {
+ std::lock_guard<std::mutex> l(this->m_cancelledMutex);
+ if (this->m_isCancelled.count(fd) == 1 && this->m_isCancelled[fd])
+ ThrowExcInfo(ASYNC_EVENT_CANCEL, "operation cancelled on fd: " << fd);
+ });
}
- case CommandId::SET_DIR_TIMESTAMP: {
- hasPermission(conn);
-
- std::string dir;
- int64_t ts64 = 0;
- q.Deserialize(dir, ts64);
+ case CommandId::CANCEL_OPERATION: {
+ std::lock_guard<std::mutex> l(this->m_cancelledMutex);
+ auto fd = conn->getFd();
+ if (this->m_isCancelled.count(fd) == 1) {
+ this->m_isCancelled[fd] = true;
+ INFO("Turn on cancelled flag of fd: " << fd);
+ } else {
+ WARN("Nothing to cancel... fd: " << fd);
+ }
- return this->m_cslogic->setDirTimestamp(dir, static_cast<time_t>(ts64));
+ return RawBuffer();
}
case CommandId::JUDGE_STATUS: {
diff --git a/test/internals/test-db.cpp b/test/internals/test-db.cpp
index 4ed8387..b493991 100644
--- a/test/internals/test-db.cpp
+++ b/test/internals/test-db.cpp
@@ -155,14 +155,14 @@ BOOST_AUTO_TEST_CASE(detected_malware_file)
auto detectedList = db.getDetectedAllByNameOnDir("/opt", 0);
ASSERT_IF(detectedList.empty(), true);
- db.insertDetectedFile(malware1.targetName, malware1, initDataVersion);
+ db.insertDetectedFile(malware1, initDataVersion);
detected = db.getDetectedAllByNameOnPath(malware1.targetName, 0);
CHECK_IS_NOT_NULL(detected);
checkSameMalware(malware1, *detected);
ASSERT_IF(detected->dataVersion, initDataVersion);
ASSERT_IF(detected->isIgnored, false);
- db.insertDetectedFile(malware2.targetName, malware2, initDataVersion);
+ db.insertDetectedFile(malware2, initDataVersion);
db.updateIgnoreFlag(malware2.targetName, true);
detected = db.getDetectedAllByNameOnPath(malware2.targetName, 0);
CHECK_IS_NOT_NULL(detected);
@@ -170,7 +170,7 @@ BOOST_AUTO_TEST_CASE(detected_malware_file)
ASSERT_IF(detected->dataVersion, initDataVersion);
ASSERT_IF(detected->isIgnored, true);
- db.insertDetectedFile(malware3.targetName, malware3, initDataVersion);
+ db.insertDetectedFile(malware3, initDataVersion);
db.updateIgnoreFlag(malware3.targetName, true);
detected = db.getDetectedAllByNameOnPath(malware3.targetName, 0);
CHECK_IS_NOT_NULL(detected);
@@ -200,7 +200,7 @@ BOOST_AUTO_TEST_CASE(detected_malware_file)
ASSERT_IF(detected->isIgnored, true);
// deleteDeprecatedDetectedMalwares test
- db.insertDetectedFile(malware4.targetName, malware4, changedDataVersion);
+ db.insertDetectedFile(malware4, changedDataVersion);
db.deleteDetectedDeprecated(3);
detected = db.getDetectedAllByNameOnPath(malware4.targetName, 0);
CHECK_IS_NOT_NULL(detected);
diff --git a/test/test-api-content-screening-async.cpp b/test/test-api-content-screening-async.cpp
index c91769a..888efb1 100644
--- a/test/test-api-content-screening-async.cpp
+++ b/test/test-api-content-screening-async.cpp
@@ -957,8 +957,8 @@ BOOST_AUTO_TEST_CASE(get_malware_after_async)
set_default_callback(context);
const char *dirs[4] = {
- "/opt/usr/media/",
- "/opt/usr/apps/",
+ TEST_DIR_MEDIA(),
+ TEST_DIR_APPS(),
"/tmp/",
"/sdcard/"
};