Add table to db schema to manage separately to ordinary app scanning.
It's for giving detected/ignored/judge malwares because those work based
on history in db.
Change-Id: I78fec4b61ed7838298ec156dc2452ed7c4e64c6c
Signed-off-by: Kyungwook Tak <k.tak@samsung.com>
UNIQUE(file_path)
);
+CREATE TABLE IF NOT EXISTS DETECTED_MALWARE_CLOUD (
+ idx INTEGER NOT NULL,
+ pkg_id TEXT NOT NULL,
+ data_version TEXT NOT NULL,
+ malware_name TEXT NOT NULL,
+ detailed_url TEXT NOT NULL,
+ severity INTEGER NOT NULL,
+ detected_time INTEGER NOT NULL,
+
+ FOREIGN KEY(idx) REFERENCES NAMES(idx) ON DELETE CASCADE
+);
+
CREATE TABLE IF NOT EXISTS PACKAGE_INFO (
pkg_id TEXT NOT NULL,
idx INTEGER NOT NULL,
FOREIGN KEY(worst_filepath_idx) REFERENCES DETECTED_MALWARE(filepath_idx) ON DELETE CASCADE
);
+CREATE VIEW IF NOT EXISTS [join_detecteds_cloud_by_name] AS
+ SELECT N.name, D.data_version, D.malware_name, D.detailed_url, D.severity,
+ D.detected_time, D.pkg_id, N.is_ignored
+ FROM NAMES AS N INNER JOIN DETECTED_MALWARE_CLOUD AS D ON N.idx = D.idx;
+
CREATE VIEW IF NOT EXISTS [join_p_d] AS
SELECT N.idx, N.name, D.file_path, D.data_version, D.malware_name, D.detailed_url,
D.severity, D.detected_time, P.pkg_id
AS J INNER JOIN NAMES AS N ON J.idx = N.idx;
CREATE INDEX IF NOT EXISTS d_name_index ON DETECTED_MALWARE(idx);
+CREATE INDEX IF NOT EXISTS c_name_index ON DETECTED_MALWARE_CLOUD(idx);
CREATE INDEX IF NOT EXISTS p_name_index ON PACKAGE_INFO(idx);
CREATE INDEX IF NOT EXISTS p_filepath_index ON PACKAGE_INFO(worst_filepath_idx);
DROP INDEX IF EXISTS d_name_index;
+DROP INDEX IF EXISTS c_name_index;
DROP INDEX IF EXISTS p_name_index;
DROP INDEX IF EXISTS p_filepath_index;
+DROP VIEW IF EXISTS join_detecteds_cloud_by_name;
DROP VIEW IF EXISTS join_detecteds_by_file_path;
DROP VIEW IF EXISTS join_detecteds_by_name;
DROP VIEW IF EXISTS join_p_d;
DROP TABLE IF EXISTS PACKAGE_INFO;
+DROP TABLE IF EXISTS DETECTED_MALWARE_CLOUD;
DROP TABLE IF EXISTS DETECTED_MALWARE;
DROP TABLE IF EXISTS NAMES;
DROP TABLE IF EXISTS SCAN_REQUEST;
return row;
}
+RowShPtr extractRowCloud(Statement &stmt)
+{
+ RowShPtr row = std::make_shared<Row>();
+
+ row->targetName = stmt.getText(); // name.
+ row->fileInAppPath.clear();
+ row->dataVersion = stmt.getText(); // data_version
+ row->malwareName = stmt.getText(); // malware_name
+ row->detailedUrl = stmt.getText(); // detailed_url
+ row->severity = static_cast<csr_cs_severity_level_e>(stmt.getInt()); // severity
+ row->ts = static_cast<time_t>(stmt.getInt64()); // detected_time
+ row->pkgId = stmt.getText(); // pkg_id
+ row->isApp = true;
+ row->isIgnored = static_cast<bool>(stmt.getInt());
+
+ return row;
+}
+
} // namespace anonymous
Manager::Manager(const std::string &dbfile, const std::string &scriptsDir) :
return extractRow(stmt);
}
+RowShPtr Manager::getDetectedCloudByNameOnPath(const std::string &path)
+{
+ Statement stmt(this->m_conn, Query::SEL_DETECTED_CLOUD_BY_NAME_ON_PATH);
+ stmt.bind(path);
+
+ if (!stmt.step())
+ return nullptr;
+
+ return extractRowCloud(stmt);
+}
+
RowShPtrs Manager::getDetectedByNameOnDir(const std::string &dir)
{
Statement stmt(this->m_conn, Query::SEL_DETECTED_BY_NAME_ON_DIR);
return rows;
}
+RowShPtrs Manager::getDetectedCloudByNameOnDir(const std::string &dir)
+{
+ Statement stmt(this->m_conn, Query::SEL_DETECTED_CLOUD_BY_NAME_ON_DIR);
+ stmt.bind(dir);
+
+ RowShPtrs rows;
+ while (stmt.step())
+ rows.emplace_back(extractRowCloud(stmt));
+
+ return rows;
+}
+
+RowShPtrs Manager::getDetectedAllByNameOnDir(const std::string &dir)
+{
+ auto normals = this->getDetectedByNameOnDir(dir);
+ auto clouds = this->getDetectedCloudByNameOnDir(dir);
+
+ if (clouds.empty())
+ return normals;
+
+ RowShPtrs rows;
+
+ for (const auto &cloud : clouds) {
+ bool found = false;
+ auto it = normals.begin();
+
+ while (it != normals.end()) {
+ if ((*it)->targetName == cloud->targetName) {
+ rows.emplace_back(std::move(*it));
+ it = normals.erase(it);
+ found = true;
+ break;
+ } else {
+ ++it;
+ }
+ }
+
+ if (!found)
+ rows.push_back(cloud);
+ }
+
+ for (auto &&normal : normals)
+ rows.emplace_back(std::move(normal));
+
+ return rows;
+}
+
RowShPtrs Manager::getDetectedByFilepathOnDir(const std::string &dir)
{
Statement stmt(this->m_conn, Query::SEL_DETECTED_BY_FILEPATH_ON_DIR);
stmt.exec();
}
+void Manager::insertDetectedCloud(const CsDetected &d, const std::string &pkgId,
+ const std::string &name, const std::string &dataVersion)
+{
+ Statement stmt(this->m_conn, Query::INS_DETECTED_CLOUD);
+
+ stmt.bind(name);
+ stmt.bind(pkgId);
+ stmt.bind(dataVersion);
+ stmt.bind(d.malwareName);
+ stmt.bind(d.detailedUrl);
+ stmt.bind(static_cast<int>(d.severity));
+ stmt.bind(static_cast<sqlite3_int64>(d.ts));
+ stmt.exec();
+}
+
void Manager::insertWorst(const std::string &pkgId, const std::string &name,
const std::string &filepath)
{
// DETECTED_MALWARE_FILE & USER_RESPONSE
RowShPtr getDetectedByNameOnPath(const std::string &path);
+ RowShPtr getDetectedCloudByNameOnPath(const std::string &path);
RowShPtrs getDetectedByNameOnDir(const std::string &dir);
+ RowShPtrs getDetectedCloudByNameOnDir(const std::string &dir);
+ RowShPtrs getDetectedAllByNameOnDir(const std::string &dir);
RowShPtrs getDetectedByFilepathOnDir(const std::string &dir);
RowShPtr getWorstByPkgPath(const std::string &pkgPath);
void insertName(const std::string &name);
- void insertDetected(const CsDetected &, const std::string &filename,
+ void insertDetected(const CsDetected &d, const std::string &filename,
const std::string &dataVersion);
+ void insertDetectedCloud(const CsDetected &d, const std::string &pkgId,
+ const std::string &name, const std::string &dataVersion);
void insertWorst(const std::string &pkgId, const std::string &name,
const std::string &filepath);
const std::string DEL_SCAN_REQUEST =
"delete from SCAN_REQUEST";
+const std::string SEL_DETECTED_CLOUD_BY_NAME_ON_PATH =
+ "select name, data_version, malware_name, detailed_url, severity, detected_time,"
+ " pkg_id, is_ignored"
+ " from join_detecteds_cloud_by_name"
+ " where name = ?";
+
const std::string SEL_DETECTED_BY_NAME_ON_PATH =
"select name, file_path, data_version, malware_name, detailed_url, severity,"
" detected_time, pkg_id, is_ignored"
" from join_detecteds_by_name"
" where name = ?";
+const std::string SEL_DETECTED_CLOUD_BY_NAME_ON_DIR =
+ "select name, data_version, malware_name, detailed_url, severity, detected_time,"
+ " pkg_id, is_ignored"
+ " from join_detecteds_cloud_by_name"
+ " where name like ? || '%'";
+
const std::string SEL_DETECTED_BY_NAME_ON_DIR =
"select name, file_path, data_version, malware_name, detailed_url, severity,"
" detected_time, pkg_id, is_ignored"
const std::string INS_NAME =
"insert or replace into NAMES(name) values(?)";
+const std::string INS_DETECTED_CLOUD =
+ "insert or replace into DETECTED_MALWARE_CLOUD(idx, pkg_id, data_version,"
+ " malware_name, detailed_url, severity,"
+ " detected_time)"
+ " values((select idx from NAMES where name = ?), ?, ?, ?, ?, ?, ?)";
+
const std::string INS_DETECTED =
"insert or replace into DETECTED_MALWARE(file_path, idx, data_version, malware_name,"
" detailed_url, severity, detected_time)"
detected.isApp = true;
detected.pkgId = pkgId;
+ this->m_db->insertName(pkgPath);
+ this->m_db->insertDetectedCloud(detected, pkgId, pkgPath, this->m_dataVersion);
+
return this->handleAskUser(context, detected);
}
if (lastScanTime != -1) {
// for case: scan history exist and not modified.
- for (auto &row : this->m_db->getDetectedByNameOnDir(File::getPkgPath(dir))) {
+ for (auto &row : this->m_db->getDetectedAllByNameOnDir(File::getPkgPath(dir))) {
try {
auto fileptr = File::create(row->targetName);
auto history = this->m_db->getDetectedByNameOnPath(targetName);
+ bool isCloudHistory = false;
+
if (!history) {
- ERROR("Target to be judged doesn't exist in db. name: " << targetName);
- return BinaryQueue::Serialize(CSR_ERROR_INVALID_PARAMETER).pop();
+ history = this->m_db->getDetectedCloudByNameOnPath(targetName);
+
+ if (!history) {
+ ERROR("Target to be judged doesn't exist in db. name: " << targetName);
+ return BinaryQueue::Serialize(CSR_ERROR_INVALID_PARAMETER).pop();
+ }
+
+ isCloudHistory = true;
}
// file create based on fileInAppPath(for app target, it is worst detected)
- if (File::createIfModified(history->fileInAppPath, static_cast<time_t>(history->ts)))
+ if (!isCloudHistory && File::createIfModified(history->fileInAppPath,
+ static_cast<time_t>(history->ts)))
ThrowExc(CSR_ERROR_FILE_CHANGED,
"File[" << history->fileInAppPath << "] modified since db delta inserted."
" Don't refresh detected history to know that it's changed since the"
}
auto row = this->m_db->getDetectedByNameOnPath(target);
+ if (!row)
+ row = this->m_db->getDetectedCloudByNameOnPath(target);
if (row && !row->isIgnored)
return BinaryQueue::Serialize(CSR_ERROR_NONE, row).pop();
Db::RowShPtrs rows;
for (const auto &dir : dirSet) {
- for (auto &row : this->m_db->getDetectedByNameOnDir(dir)) {
- if (!isReadable(row->targetName)) {
+ for (auto &row : this->m_db->getDetectedAllByNameOnDir(dir)) {
+ if (!row->fileInAppPath.empty() && !isReadable(row->targetName)) {
WARN("Exclude not-accessable malware detected file from the list: " <<
row->targetName);
this->m_db->deleteDetectedByNameOnPath(row->targetName);
}
auto row = this->m_db->getDetectedByNameOnPath(target);
+ if (!row)
+ row = this->m_db->getDetectedCloudByNameOnPath(target);
if (row && row->isIgnored)
return BinaryQueue::Serialize(CSR_ERROR_NONE, row).pop();
Db::RowShPtrs rows;
for (const auto &dir : dirSet) {
- for (auto &row : this->m_db->getDetectedByNameOnDir(dir)) {
- if (!isReadable(row->targetName)) {
+ for (auto &row : this->m_db->getDetectedAllByNameOnDir(dir)) {
+ if (!row->fileInAppPath.empty() && !isReadable(row->targetName)) {
WARN("Exclude not-accessable malware detected file from the list: " <<
row->targetName);
this->m_db->deleteDetectedByNameOnPath(row->targetName);
case CSRE_ERROR_NONE:
return;
+ case CSRE_ERROR_INVALID_PARAMETER:
+ ThrowExc(CSR_ERROR_ENGINE_INTERNAL, "CSRE_ERROR_INVALID_PARAMETER!");
+
case CSRE_ERROR_OUT_OF_MEMORY:
throw std::bad_alloc();
+ case CSRE_ERROR_INVALID_HANDLE:
+ ThrowExc(CSR_ERROR_ENGINE_INTERNAL, "CSRE_ERROR_INVALID_HANDLE!");
+
+ case CSRE_ERROR_ENGINE_NOT_ACTIVATED:
+ ThrowExc(CSR_ERROR_ENGINE_NOT_ACTIVATED, "engine is not activated yet");
+
case CSRE_ERROR_PERMISSION_DENIED:
ThrowExc(CSR_ERROR_ENGINE_PERMISSION, "access denied related to engine");
case CSRE_ERROR_FILE_NOT_FOUND:
ThrowExc(CSR_ERROR_FILE_DO_NOT_EXIST, "file not found.");
- case CSRE_ERROR_ENGINE_NOT_ACTIVATED:
- ThrowExc(CSR_ERROR_ENGINE_NOT_ACTIVATED, "engine is not activated yet");
+ case CSRE_ERROR_NO_DATA:
+ ThrowExc(CSR_ERROR_ENGINE_INTERNAL, "CSRE_ERROR_NO_DATA!");
+
+ case CSRE_ERROR_UNKNOWN:
+ ThrowExc(CSR_ERROR_ENGINE_INTERNAL, "CSRE_ERROR_UNKNOWN!");
default:
if (internalErrorToString) {
if (handle == nullptr || app_root_dir == nullptr || pdetected == nullptr)
return CSRE_ERROR_INVALID_PARAMETER;
- int ret;
csre_cs_detected_h detected = nullptr;
csre_cs_detected_h most_detected = nullptr;
csre_cs_severity_level_e most = CSRE_CS_SEVERITY_LOW;
std::unique_ptr<DIR, std::function<int(DIR *)>> dirp(opendir(app_root_dir),
closedir);
- if (!dirp)
- return CSRE_ERROR_FILE_NOT_FOUND;
+ if (!dirp) {
+ // silently skip the subdirectory in app_root_dir that unable to open because of
+ // having no permission
+ *pdetected = nullptr;
+ return CSRE_ERROR_NONE;
+ }
struct dirent entry;
struct dirent *result;
fullpath += "/";
fullpath += filename;
+ int ret = CSRE_ERROR_NONE;
+
if (entry.d_type & (DT_REG | DT_LNK))
ret = csre_cs_scan_file(handle, fullpath.c_str(), &detected);
else if ((entry.d_type & DT_DIR)
}
}
- *pdetected = reinterpret_cast<csre_cs_detected_h>(detected);
+ *pdetected = most_detected;
- return ret;
+ return CSRE_ERROR_NONE;
}
//==============================================================================
TEST_FILE_HIGH, MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY, MALWARE_HIGH_DETAILED_URL);
ASSERT_DETECTED_IN_LIST_EXT(testCtx.detectedList, TEST_FILE_HIGH, false, "");
- ASSERT_DETECTED_IN_LIST(testCtx.detectedList,
- TEST_FILE_MEDIUM, MALWARE_MEDIUM_NAME, MALWARE_MEDIUM_SEVERITY, MALWARE_MEDIUM_DETAILED_URL);
+ ASSERT_DETECTED_IN_LIST(testCtx.detectedList, TEST_FILE_MEDIUM, MALWARE_MEDIUM_NAME,
+ MALWARE_MEDIUM_SEVERITY, MALWARE_MEDIUM_DETAILED_URL);
ASSERT_DETECTED_IN_LIST_EXT(testCtx.detectedList, TEST_FILE_MEDIUM, false, "");
- ASSERT_DETECTED_IN_LIST(testCtx.detectedList,
- TEST_FILE_LOW, MALWARE_LOW_NAME, MALWARE_LOW_SEVERITY, MALWARE_LOW_DETAILED_URL);
+ ASSERT_DETECTED_IN_LIST(testCtx.detectedList, TEST_FILE_LOW, MALWARE_LOW_NAME,
+ MALWARE_LOW_SEVERITY, MALWARE_LOW_DETAILED_URL);
ASSERT_DETECTED_IN_LIST_EXT(testCtx.detectedList, TEST_FILE_LOW, false, "");
EXCEPTION_GUARD_END
BOOST_REQUIRE_MESSAGE(testRescanCtx.scannedCnt >= 1,
"reinstalled app(non-malicious wgt) should be counted in scanned.");
- ASSERT_DETECTED_IN_LIST(testRescanCtx.detectedList,
- TEST_WGT_APP_ROOT(), MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY, MALWARE_HIGH_DETAILED_URL);
- ASSERT_DETECTED_IN_LIST_EXT(testRescanCtx.detectedList, TEST_WGT_APP_ROOT(), true, TEST_WGT_PKG_ID);
+ ASSERT_DETECTED_IN_LIST(testRescanCtx.detectedList, TEST_WGT_APP_ROOT(),
+ MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY,
+ MALWARE_HIGH_DETAILED_URL);
+ ASSERT_DETECTED_IN_LIST_EXT(testRescanCtx.detectedList, TEST_WGT_APP_ROOT(), true,
+ TEST_WGT_PKG_ID);
- ASSERT_DETECTED_IN_LIST(testRescanCtx.detectedList,
- TEST_TPK_APP_ROOT(), MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY, MALWARE_HIGH_DETAILED_URL);
- ASSERT_DETECTED_IN_LIST_EXT(testRescanCtx.detectedList, TEST_TPK_APP_ROOT(), true, TEST_TPK_PKG_ID);
+ ASSERT_DETECTED_IN_LIST(testRescanCtx.detectedList, TEST_TPK_APP_ROOT(),
+ MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY,
+ MALWARE_HIGH_DETAILED_URL);
+ ASSERT_DETECTED_IN_LIST_EXT(testRescanCtx.detectedList, TEST_TPK_APP_ROOT(), true,
+ TEST_TPK_PKG_ID);
- ASSERT_DETECTED_IN_LIST(testRescanCtx.detectedList,
- TEST_FAKE_APP_FILE(), MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY, MALWARE_HIGH_DETAILED_URL);
- ASSERT_DETECTED_IN_LIST_EXT(testRescanCtx.detectedList, TEST_FAKE_APP_FILE(), false, "");
+ ASSERT_DETECTED_IN_LIST(testRescanCtx.detectedList, TEST_FAKE_APP_FILE(),
+ MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY,
+ MALWARE_HIGH_DETAILED_URL);
+ ASSERT_DETECTED_IN_LIST_EXT(testRescanCtx.detectedList, TEST_FAKE_APP_FILE(), false,
+ "");
uninstall_test_apps();
EXCEPTION_GUARD_END
}
+BOOST_AUTO_TEST_CASE(scan_app_on_cloud)
+{
+ EXCEPTION_GUARD_START
+
+ BOOST_MESSAGE("Only valid for engines which supports scan on cloud feature");
+
+ auto c = Test::Context<csr_cs_context_h>();
+ auto context = c.get();
+
+ install_test_files();
+ install_test_apps();
+
+ set_default_callback(context);
+ ASSERT_SUCCESS(csr_cs_set_scan_on_cloud(context, true));
+
+ AsyncTestContext testCtx;
+
+ ASSERT_SUCCESS(csr_cs_scan_dir_async(context, TEST_DIR_APPS(), &testCtx));
+
+ std::unique_lock<std::mutex> l(testCtx.m);
+ testCtx.cv.wait(l);
+ l.unlock();
+
+ ASSERT_CALLBACK(testCtx, -1, -1, 1, 0, 0);
+
+ ASSERT_DETECTED_IN_LIST(testCtx.detectedList, TEST_WGT_APP_ROOT(),
+ MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY,
+ MALWARE_HIGH_DETAILED_URL);
+ ASSERT_DETECTED_IN_LIST_EXT(testCtx.detectedList, TEST_WGT_APP_ROOT(), true,
+ TEST_WGT_PKG_ID);
+
+ ASSERT_DETECTED_IN_LIST(testCtx.detectedList, TEST_TPK_APP_ROOT(),
+ MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY,
+ MALWARE_HIGH_DETAILED_URL);
+ ASSERT_DETECTED_IN_LIST_EXT(testCtx.detectedList, TEST_TPK_APP_ROOT(), true,
+ TEST_TPK_PKG_ID);
+
+ ASSERT_DETECTED_IN_LIST(testCtx.detectedList, TEST_FAKE_APP_FILE(),
+ MALWARE_HIGH_NAME, MALWARE_HIGH_SEVERITY,
+ MALWARE_HIGH_DETAILED_URL);
+ ASSERT_DETECTED_IN_LIST_EXT(testCtx.detectedList, TEST_FAKE_APP_FILE(), false, "");
+
+ const char *dirs[1] = {
+ TEST_DIR_APPS()
+ };
+ csr_cs_malware_list_h malwares = nullptr;
+ size_t count = 0;
+
+ ASSERT_SUCCESS(csr_cs_get_detected_malwares(context, dirs, 1, &malwares, &count));
+ CHECK_IS_NOT_NULL(malwares);
+
+ std::vector<csr_cs_malware_h> malware_vec;
+ for (size_t i = 0; i < count; ++i) {
+ csr_cs_malware_h malware = nullptr;
+ ASSERT_SUCCESS(csr_cs_malware_list_get_malware(malwares, i, &malware));
+
+ malware_vec.push_back(malware);
+ }
+
+ ASSERT_DETECTED_IN_LIST(malware_vec, TEST_WGT_APP_ROOT(), MALWARE_HIGH_NAME,
+ MALWARE_HIGH_SEVERITY, MALWARE_HIGH_DETAILED_URL);
+ ASSERT_DETECTED_IN_LIST_EXT(malware_vec, TEST_WGT_APP_ROOT(), true, TEST_WGT_PKG_ID);
+
+ ASSERT_DETECTED_IN_LIST(malware_vec, TEST_TPK_APP_ROOT(), MALWARE_HIGH_NAME,
+ MALWARE_HIGH_SEVERITY, MALWARE_HIGH_DETAILED_URL);
+ ASSERT_DETECTED_IN_LIST_EXT(malware_vec, TEST_TPK_APP_ROOT(), true, TEST_TPK_PKG_ID);
+
+ ASSERT_DETECTED_IN_LIST(malware_vec, TEST_FAKE_APP_FILE(), MALWARE_HIGH_NAME,
+ MALWARE_HIGH_SEVERITY, MALWARE_HIGH_DETAILED_URL);
+ ASSERT_DETECTED_IN_LIST_EXT(malware_vec, TEST_FAKE_APP_FILE(), false, "");
+
+ EXCEPTION_GUARD_END
+}
+
BOOST_AUTO_TEST_SUITE_END()