Add INSERT, DELETE features to osquery
authorSangwan Kwon <sangwan.kwon@samsung.com>
Tue, 29 Oct 2019 05:53:56 +0000 (14:53 +0900)
committerSangwan Kwon <sangwan.kwon@samsung.com>
Wed, 30 Oct 2019 04:46:01 +0000 (13:46 +0900)
- DELETE statement logic -
If the statement has a where clause, xFilter is called.
(otherwise, xUpdate is called directly.)
And xFilter calls VirtualTable::generate to find row matched with
the where clause.
When the row comes out, execute the delete statement through xUpdate.

Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
src/osquery/sql/virtual_table.cpp
tools/codegen/gentable.py
tools/codegen/templates/default.cpp.in

index ee2d414..6509e98 100644 (file)
@@ -125,6 +125,44 @@ bool getColumnValue(std::string& value,
   return true;
 }
 
+/// PATCH START //////////////////////////////////////////////////////////////
+int serializeDeleteParameters(std::string& json_value_array,
+                                                         VirtualTable* pVtab) {
+       auto content = pVtab->content;
+       if (content->constraints.size() <= 0) {
+               LOG(ERROR) << "Invalid constraints arguments";
+               return SQLITE_ERROR;
+       }
+
+       auto document = rapidjson::Document();
+       document.SetArray();
+       auto& allocator = document.GetAllocator();
+
+       for (std::size_t i = 0; i < content->constraints.size(); i++) {
+               for (auto& constraint : content->constraints[i]) {
+                       auto key = constraint.first;
+                       auto value = constraint.second.expr;
+
+                       if (!value.empty()) {
+                               /// Since concrete table is not able to know the key, make alias.
+                               rapidjson::Value jsonValue((key + ";" + value).c_str(), allocator);
+                               document.PushBack(jsonValue, allocator);
+                       }
+               }
+       }
+
+       rapidjson::StringBuffer buffer;
+       buffer.Clear();
+
+       rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
+       document.Accept(writer);
+
+       json_value_array = buffer.GetString();
+
+       return SQLITE_OK;
+}
+/// PATCH END /////////////////////////////////////////////////////////////////
+
 // Type-aware serializer to pass parameters between osquery and the extension
 int serializeUpdateParameters(std::string& json_value_array,
                               size_t argc,
@@ -341,6 +379,12 @@ int xUpdate(sqlite3_vtab* p,
     auto row_to_delete = sqlite3_value_int64(argv[0]);
     plugin_request.insert({"id", std::to_string(row_to_delete)});
 
+/// PATCH START //////////////////////////////////////////////////////////////
+       std::string json_value_array;
+       /// serialize constraints
+       serializeDeleteParameters(json_value_array, reinterpret_cast<VirtualTable*>(p));
+       plugin_request.insert({"json_value_array", json_value_array});
+/// PATCH END ////////////////////////////////////////////////////////////////
   } else if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
     // This is an INSERT query; if the rowid has been generated for us, we'll
     // find it inside argv[1]
@@ -464,6 +508,7 @@ int xUpdate(sqlite3_vtab* p,
     return SQLITE_ERROR;
   }
 
+/*
   // INSERT actions must always return a valid rowid to sqlite
   if (plugin_request.at("action") == "insert") {
     std::string rowid;
@@ -491,7 +536,7 @@ int xUpdate(sqlite3_vtab* p,
     }
     *pRowid = exp.take();
   }
-
+*/
   return SQLITE_OK;
 }
 
index 12895d2..b61a91f 100755 (executable)
@@ -196,6 +196,8 @@ class TableState(Singleton):
         self.header = ""
         self.impl = ""
         self.function = ""
+        self.function_delete = ""
+        self.function_insert = ""
         self.function_update = ""
         self.class_name = ""
         self.description = ""
@@ -284,6 +286,8 @@ class TableState(Singleton):
             header=self.header,
             impl=self.impl,
             function=self.function,
+            function_delete=self.function_delete,
+            function_insert=self.function_insert,
             function_update=self.function_update,
             class_name=self.class_name,
             attributes=self.attributes,
@@ -442,7 +446,35 @@ def implementation(impl_string, generator=False):
                     table.table_name, BIGINT)))
             sys.exit(1)
 
-# patched
+### patch start ###########################################################
+def implementation_delete(impl_string, generator=False):
+    if impl_string is None:
+        table.function_delete = ""
+    else:
+        filename, function_delete = impl_string.split("@")
+        class_parts = function_delete.split("::")[::-1]
+        function_delete = class_parts[0]
+        class_name = class_parts[1] if len(class_parts) > 1 else ""
+        impl = "%s.cpp" % filename
+        table.impl = impl
+        table.function_delete = function_delete
+        table.class_name = class_name
+        table.generator = generator
+
+def implementation_insert(impl_string, generator=False):
+    if impl_string is None:
+        table.function_insert = ""
+    else:
+        filename, function_insert = impl_string.split("@")
+        class_parts = function_insert.split("::")[::-1]
+        function_insert = class_parts[0]
+        class_name = class_parts[1] if len(class_parts) > 1 else ""
+        impl = "%s.cpp" % filename
+        table.impl = impl
+        table.function_insert = function_insert
+        table.class_name = class_name
+        table.generator = generator
+
 def implementation_update(impl_string, generator=False):
     if impl_string is None:
         table.function_update = ""
@@ -457,6 +489,8 @@ def implementation_update(impl_string, generator=False):
         table.class_name = class_name
         table.generator = generator
 
+### patch end #############################################################
+
 def main():
     parser = argparse.ArgumentParser(
         "Generate C++ Table Plugin from specfile.")
index d28ed88..574ce0d 100644 (file)
@@ -5,6 +5,21 @@
  *  This source code is licensed in accordance with the terms specified in
  *  the LICENSE file found in the root directory of this source tree.
  */
+/*
+ *  Copyright (c) 2019 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
+ */
 
 /*
 ** This file is generated. Do not modify it manually!
@@ -24,23 +39,26 @@ namespace tables {
 void {{function}}(RowYield& yield, QueryContext& context);
 {% elif strongly_typed_rows %}\
 osquery::TableRows {{function}}(QueryContext& context);
+{% else %}\
+osquery::QueryData {{function}}(QueryContext& context);
 
-/// patch start
-{% if function_update != "" %}\
-osquery::QueryData {{function_update}}(QueryContext& context,
+/// patch start //////////////////////////////////////////////////
+{% if function_delete != "" %}\
+osquery::QueryData {{function_delete}}(QueryContext& context,
                                        const PluginRequest& request);
 {% endif %}\
-/// patch end
 
-{% else %}\
-osquery::QueryData {{function}}(QueryContext& context);
+{% if function_insert != "" %}\
+osquery::QueryData {{function_insert}}(QueryContext& context,
+                                       const PluginRequest& request);
+{% endif %}\
 
-/// patch start
 {% if function_update != "" %}\
 osquery::QueryData {{function_update}}(QueryContext& context,
                                        const PluginRequest& request);
 {% endif %}\
-/// patch end
+
+/// patch end ///////////////////////////////////////////////////
 
 {% endif %}\
 {% else %}
@@ -144,14 +162,29 @@ class {{table_name_cc}}TablePlugin : public TablePlugin {
     return results;
   }
 
-/// patch start
+/// patch start /////////////////////////////////////////////////////
+{% if function_delete != "" %}\
+  QueryData delete_(QueryContext& context,
+                   const PluginRequest& request) override {
+    return tables::{{function_delete}}(context, request);
+  }
+{% endif %}\
+
+{% if function_insert != "" %}\
+  QueryData insert(QueryContext& context,
+                   const PluginRequest& request) override {
+    return tables::{{function_insert}}(context, request);
+  }
+{% endif %}\
+
 {% if function_update != "" %}\
   QueryData update(QueryContext& context,
                    const PluginRequest& request) override {
     return tables::{{function_update}}(context, request);
   }
 {% endif %}\
-/// patch end
+
+/// patch end ///////////////////////////////////////////////////////
 
 {% endif %}\