Support update feature with policyd
authorSangwan Kwon <sangwan.kwon@samsung.com>
Fri, 11 Oct 2019 07:59:03 +0000 (16:59 +0900)
committer권상완/Security 2Lab(SR)/Engineer/삼성전자 <sangwan.kwon@samsung.com>
Thu, 17 Oct 2019 05:04:06 +0000 (14:04 +0900)
Example: UPDATE policy SET value = '3' WHERE name = 'bluetooth'

Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
specs/tizen/policy.table
src/apix/manager/tests/manager_tests.cpp
src/osquery/CMakeLists.txt
src/osquery/sql/virtual_table.cpp
src/osquery/tables/tizen/policy.cpp
tools/codegen/gentable.py
tools/codegen/templates/default.cpp.in

index cb22e61..b51be81 100644 (file)
@@ -5,6 +5,8 @@ schema([
     Column("value", TEXT, "Policy value"),
 ])
 implementation("tizen/policy@genPolicy")
+implementation_update("tizen/policy@updatePolicy")
 examples([
   "select * from policy where name = 'bluetooth'",
+  "update policy set value = 1 where name = 'bluetooth'",
 ])
index 1a4ff23..b1b266e 100644 (file)
@@ -21,6 +21,8 @@
 #include <osquery/notification.h>
 #include <osquery/logger.h>
 
+#include <policyd/core/policy-manager.h>
+
 using namespace osquery;
 
 class ManagerTests : public testing::Test {};
@@ -59,6 +61,27 @@ TEST_F(ManagerTests, test_manager_execute_policy) {
        EXPECT_EQ(rows.size(), 1);
 }
 
+TEST_F(ManagerTests, test_manager_execute_policy_update) {
+       auto& manager = policyd::PolicyManager::Instance();
+       manager.enroll("admin", 0);
+
+       std::string query = "SELECT * FROM policy WHERE name = 'bluetooth'";
+       auto rows = OsqueryManager::execute(query);
+       /// Initial policy value
+       EXPECT_EQ(rows[0]["value"], std::to_string(1));
+
+       query = "UPDATE policy SET value = '3' WHERE name = 'bluetooth'";
+       rows = OsqueryManager::execute(query);
+       EXPECT_EQ(rows.size(), 0);
+
+       query = "SELECT * FROM policy WHERE name = 'bluetooth'";
+       rows = OsqueryManager::execute(query);
+       /// Initial policy value
+       EXPECT_EQ(rows[0]["value"], std::to_string(3));
+
+       manager.disenroll("admin", 0);
+}
+
 TEST_F(ManagerTests, test_manager_subscribe) {
        int called = 0;
        auto callback = [&](const Row& row) {
index fdee170..660bf29 100644 (file)
@@ -65,8 +65,13 @@ ADD_LIBRARY(${TARGET_OSQUERY_LIB}
                                STATIC $<TARGET_OBJECTS:osquery_generated_tables>
                                           $<TARGET_OBJECTS:osquery_sqlite>
                                           ${${TARGET_OSQUERY_LIB}_SRCS})
-TARGET_LINK_LIBRARIES(${TARGET_OSQUERY_LIB} ${${TARGET_OSQUERY_LIB}_DEPS}
-                                                                                       ${TARGET_POLICYD_LIB})
+
+TARGET_LINK_LIBRARIES(${TARGET_OSQUERY_LIB} ${${TARGET_OSQUERY_LIB}_DEPS})
+
+IF(DEFINED GBS_BUILD)
+TARGET_LINK_LIBRARIES(${TARGET_OSQUERY_LIB} ${TARGET_POLICYD_LIB})
+ENDIF(DEFINED GBS_BUILD)
+
 SET_TARGET_PROPERTIES(${TARGET_OSQUERY_LIB} PROPERTIES OUTPUT_NAME ${TARGET_OSQUERY_LIB})
 
 ADD_EXECUTABLE(${TARGET_OSQUERY_TEST} main/tests.cpp
index 5198466..ee2d414 100644 (file)
@@ -944,6 +944,7 @@ struct sqlite3_module* getVirtualTableModule(const std::string& table_name,
   sqlite_module_map[table_name].xEof = tables::sqlite::xEof;
   sqlite_module_map[table_name].xColumn = tables::sqlite::xColumn;
   sqlite_module_map[table_name].xRowid = tables::sqlite::xRowid;
+  sqlite_module_map[table_name].xUpdate = tables::sqlite::xUpdate;
 
   // Allow the table to receive INSERT/UPDATE/DROP events if it is
   // implemented from an extension and is overwriting the right methods
index b355f7d..c6bd1d1 100644 (file)
@@ -62,8 +62,34 @@ QueryData genPolicy(QueryContext& context) try {
 
        return results;
 } catch (...) {
-// TODO(Sangwan): Resolve duplicated "ERROR" macro with DPM
-//    LOG(ERROR) << "Exception occured";
+       Row r;
+       return { r };
+}
+
+QueryData updatePolicy(QueryContext& context, const PluginRequest& request) try {
+       if (request.count("json_value_array") == 0)
+               throw std::runtime_error("Wrong request format. Not found json value.");
+
+       std::string str = request.at("json_value_array");
+       rapidjson::Document document;
+       document.Parse(str.c_str());
+       if (document.HasParseError() || !document.IsArray())
+               throw std::runtime_error("Cannot parse request.");
+
+       if (document.Size() != 2)
+               throw std::runtime_error("Wrong request format.");
+
+       std::string name = document[0].GetString();
+       int value = std::stoi(document[1].GetString());
+
+       /// TODO(Sangwan): Get admin name from policyd
+       auto& manager = PolicyManager::Instance();
+       manager.set(name, PolicyValue(value), "admin");
+
+       Row r;
+       r["status"] = "success";
+       return { r };
+} catch (...) {
        Row r;
        return { r };
 }
index e9f9995..12895d2 100755 (executable)
@@ -196,6 +196,7 @@ class TableState(Singleton):
         self.header = ""
         self.impl = ""
         self.function = ""
+        self.function_update = ""
         self.class_name = ""
         self.description = ""
         self.attributes = {}
@@ -283,6 +284,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,
@@ -440,6 +442,20 @@ def implementation(impl_string, generator=False):
                     table.table_name, BIGINT)))
             sys.exit(1)
 
+# patched
+def implementation_update(impl_string, generator=False):
+    if impl_string is None:
+        table.function_update = ""
+    else:
+        filename, function_update = impl_string.split("@")
+        class_parts = function_update.split("::")[::-1]
+        function_update = class_parts[0]
+        class_name = class_parts[1] if len(class_parts) > 1 else ""
+        impl = "%s.cpp" % filename
+        table.impl = impl
+        table.function_update = function_update
+        table.class_name = class_name
+        table.generator = generator
 
 def main():
     parser = argparse.ArgumentParser(
index 1d3c7d6..61c26bb 100644 (file)
@@ -24,9 +24,28 @@ namespace tables {
 void {{function}}(RowYield& yield, QueryContext& context);
 {% elif strongly_typed_rows %}\
 osquery::TableRows {{function}}(QueryContext& context);
+
+/// patch start
+{% if function_update != "" %}\
+osquery::QueryData {{function_update}}(QueryContext& context,
+                                       const PluginRequest& request);
+/// patch end
+
+{% endif %}\
+
 {% else %}\
 osquery::QueryData {{function}}(QueryContext& context);
+
+/// patch start
+{% if function_update != "" %}\
+osquery::QueryData {{function_update}}(QueryContext& context,
+                                       const PluginRequest& request);
+/// patch end
+
 {% endif %}\
+
+{% endif %}\
+
 {% else %}
 class {{class_name}} {
  public:
@@ -127,6 +146,16 @@ class {{table_name_cc}}TablePlugin : public TablePlugin {
 {% endif %}
     return results;
   }
+
+/// patch start
+{% if function_update != "" %}\
+  QueryData update(QueryContext& context,
+                   const PluginRequest& request) override {
+    return tables::{{function_update}}(context, request);
+  }
+{% endif %}\
+/// patch end
+
 {% endif %}\
 
 };