From a39ad1bcdf2e56beb1e06314b8eba94f1facb816 Mon Sep 17 00:00:00 2001 From: Sangwan Kwon Date: Tue, 20 Aug 2019 14:27:21 +0900 Subject: [PATCH] Add command feature - Origin osquery only supports query feature (SELECT) + Tizen osquery adds command feature (UPDATE) Signed-off-by: Sangwan Kwon --- include/osquery/tables.h | 4 ++++ osquery/core/tables.cpp | 4 ++++ osquery/sql/tests/virtual_table_tests.cpp | 20 +++++++++++++++++ osquery/sql/virtual_table.cpp | 37 +++++++++++++++++++++++++------ osquery/tables/system/linux/users.cpp | 10 +++++++++ osquery/tizen/CMakeLists.txt | 2 +- specs/users.table | 1 + tools/codegen/gentable.py | 11 +++++++++ tools/codegen/templates/default.cpp.in | 14 ++++++++++++ 9 files changed, 95 insertions(+), 8 deletions(-) diff --git a/include/osquery/tables.h b/include/osquery/tables.h index b7a6369..f2db419 100644 --- a/include/osquery/tables.h +++ b/include/osquery/tables.h @@ -318,6 +318,10 @@ class TablePlugin : public Plugin { return data; } + virtual Status update(Row& row) { + return Status(0, "OK"); + } + protected: std::string columnDefinition() const; PluginResponse routeInfo() const; diff --git a/osquery/core/tables.cpp b/osquery/core/tables.cpp index b946731..d71fd22 100644 --- a/osquery/core/tables.cpp +++ b/osquery/core/tables.cpp @@ -116,6 +116,10 @@ Status TablePlugin::call(const PluginRequest& request, } } else if (request.at("action") == "definition") { response.push_back({{"definition", columnDefinition()}}); + } else if (request.at("action") == "update") { + Row row = request; + row.erase("action"); + return update(row); } else { return Status(1, "Unknown table plugin action: " + request.at("action")); } diff --git a/osquery/sql/tests/virtual_table_tests.cpp b/osquery/sql/tests/virtual_table_tests.cpp index d5ac553..c08cce6 100644 --- a/osquery/sql/tests/virtual_table_tests.cpp +++ b/osquery/sql/tests/virtual_table_tests.cpp @@ -77,4 +77,24 @@ TEST_F(VirtualTableTests, test_sqlite3_table_joins) { EXPECT_TRUE(status.ok()); EXPECT_EQ(results.size(), 1); } + +TEST_F(VirtualTableTests, test_sqlite3_table_update_where) { + // Get a database connection. + auto dbc = SQLiteDBManager::get(); + + QueryData results; + std::string statement = "UPDATE users SET uid = 1234, gid = 232 WHERE uid = 0"; + auto status = queryInternal(statement, results, dbc.db()); + EXPECT_TRUE(status.ok()); +} + +TEST_F(VirtualTableTests, test_sqlite3_table_update) { + // Get a database connection. + auto dbc = SQLiteDBManager::get(); + + QueryData results; + std::string statement = "UPDATE users SET uid = 1234, gid = 232"; + auto status = queryInternal(statement, results, dbc.db()); + EXPECT_TRUE(status.ok()); +} } diff --git a/osquery/sql/virtual_table.cpp b/osquery/sql/virtual_table.cpp index c8b62a0..1a51ad9 100644 --- a/osquery/sql/virtual_table.cpp +++ b/osquery/sql/virtual_table.cpp @@ -62,6 +62,35 @@ int xRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid) { return SQLITE_OK; } +int xUpdate(sqlite3_vtab *pVTab, + int argc, + sqlite3_value **argv, + sqlite3_int64 *pRowid) +{ + auto * pVtab = (VirtualTable *)pVTab; + if (argc <= 1 || argc - 2 != pVtab->content->columns.size()) { + LOG(ERROR) << "Invalid arguments: " << argc; + return SQLITE_ERROR; + } + + PluginRequest request = {{"action", "update"}}; + const auto& columns = pVtab->content->columns; + for (size_t i = 2; i < static_cast(argc); ++i) { + auto expr = (const char *)sqlite3_value_text(argv[i]); + if (expr == nullptr) { + // SQLite did not expose the expression value. + continue; + } else { + request.insert(std::make_pair(columns[i - 2].first, std::string(expr))); + } + } + + PluginResponse response; + Registry::call("table", pVtab->content->name, request, response); + + return SQLITE_OK; +} + int xCreate(sqlite3 *db, void *pAux, int argc, @@ -278,13 +307,7 @@ Status attachTableInternal(const std::string &name, tables::xEof, tables::xColumn, tables::xRowid, - 0, - 0, - 0, - 0, - 0, - 0, - 0, + tables::xUpdate, }; // clang-format on diff --git a/osquery/tables/system/linux/users.cpp b/osquery/tables/system/linux/users.cpp index a816bac..6108987 100644 --- a/osquery/tables/system/linux/users.cpp +++ b/osquery/tables/system/linux/users.cpp @@ -17,6 +17,8 @@ #include #include +#include +#include namespace osquery { namespace tables { @@ -50,5 +52,13 @@ QueryData genUsers(QueryContext& context) { return results; } + +/// Example of update feature +Status updateUsers(Row& row) { + for (auto& r : row) + LOG(ERROR) << "DEBUG: " << r.first << ", " << r.second; + + return Status(0, "OK"); +} } } diff --git a/osquery/tizen/CMakeLists.txt b/osquery/tizen/CMakeLists.txt index 8cb3170..669f1bb 100644 --- a/osquery/tizen/CMakeLists.txt +++ b/osquery/tizen/CMakeLists.txt @@ -17,13 +17,13 @@ ADD_OSQUERY_LIBRARY(osquery_tizen property/property.cpp manager/manager_impl.cpp notification/notification.cpp) -FILE(GLOB OSQUERY_TIZEN_TESTS "[!d]*/tests/*.cpp") ADD_OSQUERY_TEST(${OSQUERY_TIZEN_TESTS}) IF(DEFINED GBS_BUILD) # tables FILE(GLOB TIZEN_TABLES "tables/*.cpp") ADD_OSQUERY_LIBRARY(tizen_tables ${TIZEN_TABLES}) + FILE(GLOB OSQUERY_TIZEN_TESTS "[!d]*/tests/*.cpp") # Verification can be done with full-DPM # FILE(GLOB OSQUERY_GBS_TESTS "device_policy/tests/*.cpp") diff --git a/specs/users.table b/specs/users.table index 99be598..e5dab55 100644 --- a/specs/users.table +++ b/specs/users.table @@ -11,6 +11,7 @@ schema([ Column("shell", TEXT, "User's configured default shell"), ]) implementation("users@genUsers") +implementation_update("users@updateUsers") examples([ "select * from users where uid = 1000", "select * from users where username = 'root'", diff --git a/tools/codegen/gentable.py b/tools/codegen/gentable.py index b7fb75f..163f37a 100755 --- a/tools/codegen/gentable.py +++ b/tools/codegen/gentable.py @@ -141,6 +141,7 @@ class TableState(Singleton): self.header = "" self.impl = "" self.function = "" + self.function_update = "" self.class_name = "" self.description = "" self.attributes = {} @@ -162,6 +163,7 @@ class TableState(Singleton): header=self.header, impl=self.impl, function=self.function, + function_update=self.function_update, class_name=self.class_name, attributes=self.attributes, examples=self.examples, @@ -311,6 +313,15 @@ def implementation(impl_string): sys.exit(1) +def implementation_update(impl_string=None): + if impl_string is None: + table.function_update = "" + else: + filename, function = impl_string.split("@") + class_parts = function.split("::")[::-1] + table.function_update = class_parts[0] + + def main(argc, argv): parser = argparse.ArgumentParser("Generate C++ Table Plugin from specfile.") parser.add_argument( diff --git a/tools/codegen/templates/default.cpp.in b/tools/codegen/templates/default.cpp.in index 473f574..348843c 100644 --- a/tools/codegen/templates/default.cpp.in +++ b/tools/codegen/templates/default.cpp.in @@ -14,6 +14,7 @@ #include #include +#include namespace osquery { @@ -21,10 +22,16 @@ namespace osquery { namespace tables { {% if class_name == "" %}\ osquery::QueryData {{function}}(QueryContext& request); +{% if function_update != "" %}\ +osquery::Status {{function_update}}(Row& row); +{% endif %}\ {% else %} class {{class_name}} { public: osquery::QueryData {{function}}(QueryContext& request); +{% if function_update != "" %}\ + osquery::Status {{function_update}}(Row& row); +{% endif %}\ }; {% endif %}\ } @@ -52,8 +59,15 @@ class {{table_name_cc}}TablePlugin : public TablePlugin { return tables::{{function}}(request); {% endif %}\ } + +{% if function_update != "" %}\ + Status update(Row& row) { + return tables::{{function_update}}(row); + } +{% endif %}\ }; + {% if attributes.utility %} REGISTER_INTERNAL({{table_name_cc}}TablePlugin, "table", "{{table_name}}"); {% else %} -- 2.7.4