/src/osquery/osquery/sql/sqlite_util.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * Copyright (c) 2014-present, The osquery authors |
3 | | * |
4 | | * This source code is licensed as defined by the LICENSE file found in the |
5 | | * root directory of this source tree. |
6 | | * |
7 | | * SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only) |
8 | | */ |
9 | | |
10 | | #include "osquery/sql/sqlite_util.h" |
11 | | #include "osquery/sql/virtual_table.h" |
12 | | |
13 | | #include <osquery/core/plugins/sql.h> |
14 | | |
15 | | #include <osquery/utils/conversions/castvariant.h> |
16 | | |
17 | | #include <osquery/core/core.h> |
18 | | #include <osquery/core/flags.h> |
19 | | #include <osquery/core/shutdown.h> |
20 | | #include <osquery/logger/logger.h> |
21 | | #include <osquery/registry/registry_factory.h> |
22 | | #include <osquery/sql/sql.h> |
23 | | |
24 | | #include <osquery/utils/conversions/split.h> |
25 | | |
26 | | #include <boost/lexical_cast.hpp> |
27 | | |
28 | | namespace osquery { |
29 | | |
30 | | CLI_FLAG(string, |
31 | | disable_tables, |
32 | | "", |
33 | | "Comma-delimited list of table names to be disabled"); |
34 | | |
35 | | CLI_FLAG(string, |
36 | | enable_tables, |
37 | | "", |
38 | | "Comma-delimited list of table names to be enabled"); |
39 | | |
40 | | FLAG(string, nullvalue, "", "Set string for NULL values, default ''"); |
41 | | |
42 | | using OpReg = QueryPlanner::Opcode::Register; |
43 | | |
44 | | using SQLiteDBInstanceRef = std::shared_ptr<SQLiteDBInstance>; |
45 | | |
46 | | /** |
47 | | * @brief A map of SQLite status codes to their corresponding message string |
48 | | * |
49 | | * Details of this map are defined at: http://www.sqlite.org/c3ref/c_abort.html |
50 | | */ |
51 | | // clang-format off |
52 | | const std::map<int, std::string> kSQLiteReturnCodes = { |
53 | | {0, "SQLITE_OK"}, {1, "SQLITE_ERROR"}, {2, "SQLITE_INTERNAL"}, |
54 | | {3, "SQLITE_PERM"}, {4, "SQLITE_ABORT"}, {5, "SQLITE_BUSY"}, |
55 | | {6, "SQLITE_LOCKED"}, {7, "SQLITE_NOMEM"}, {8, "SQLITE_READONLY"}, |
56 | | {9, "SQLITE_INTERRUPT"}, {10, "SQLITE_IOERR"}, {11, "SQLITE_CORRUPT"}, |
57 | | {12, "SQLITE_NOTFOUND"}, {13, "SQLITE_FULL"}, {14, "SQLITE_CANTOPEN"}, |
58 | | {15, "SQLITE_PROTOCOL"}, {16, "SQLITE_EMPTY"}, {17, "SQLITE_SCHEMA"}, |
59 | | {18, "SQLITE_TOOBIG"}, {19, "SQLITE_CONSTRAINT"}, {20, "SQLITE_MISMATCH"}, |
60 | | {21, "SQLITE_MISUSE"}, {22, "SQLITE_NOLFS"}, {23, "SQLITE_AUTH"}, |
61 | | {24, "SQLITE_FORMAT"}, {25, "SQLITE_RANGE"}, {26, "SQLITE_NOTADB"}, |
62 | | {27, "SQLITE_NOTICE"}, {28, "SQLITE_WARNING"}, {100, "SQLITE_ROW"}, |
63 | | {101, "SQLITE_DONE"}, |
64 | | }; |
65 | | |
66 | | const std::map<std::string, std::string> kMemoryDBSettings = { |
67 | | {"synchronous", "OFF"}, {"count_changes", "OFF"}, |
68 | | {"default_temp_store", "0"}, {"auto_vacuum", "FULL"}, |
69 | | {"journal_mode", "OFF"}, {"cache_size", "0"}, |
70 | | {"page_count", "0"}, |
71 | | }; |
72 | | // clang-format on |
73 | | |
74 | | #define OpComparator(x) \ |
75 | | { x, QueryPlanner::Opcode(OpReg::P2, INTEGER_TYPE) } |
76 | | #define Arithmetic(x) \ |
77 | | { x, QueryPlanner::Opcode(OpReg::P3, BIGINT_TYPE) } |
78 | | |
79 | | /** |
80 | | * @brief A map from opcode to pair of result register and resultant type. |
81 | | * |
82 | | * For most opcodes we can deduce a column type based on an interred input |
83 | | * to the opcode "function". These come in a few sets, arithmetic operators, |
84 | | * comparators, aggregates, and copies. |
85 | | */ |
86 | | const std::map<std::string, QueryPlanner::Opcode> kSQLOpcodes = { |
87 | | {"Concat", QueryPlanner::Opcode(OpReg::P3, TEXT_TYPE)}, |
88 | | {"AggStep", QueryPlanner::Opcode(OpReg::P3, BIGINT_TYPE)}, |
89 | | {"AggStep0", QueryPlanner::Opcode(OpReg::P3, BIGINT_TYPE)}, |
90 | | {"Integer", QueryPlanner::Opcode(OpReg::P2, INTEGER_TYPE)}, |
91 | | {"Int64", QueryPlanner::Opcode(OpReg::P2, BIGINT_TYPE)}, |
92 | | {"String", QueryPlanner::Opcode(OpReg::P2, TEXT_TYPE)}, |
93 | | {"String8", QueryPlanner::Opcode(OpReg::P2, TEXT_TYPE)}, |
94 | | {"Or", QueryPlanner::Opcode(OpReg::P3, INTEGER_TYPE)}, |
95 | | {"And", QueryPlanner::Opcode(OpReg::P3, INTEGER_TYPE)}, |
96 | | |
97 | | // Arithmetic yields a BIGINT for safety. |
98 | | Arithmetic("BitAnd"), |
99 | | Arithmetic("BitOr"), |
100 | | Arithmetic("ShiftLeft"), |
101 | | Arithmetic("ShiftRight"), |
102 | | Arithmetic("Add"), |
103 | | Arithmetic("Subtract"), |
104 | | Arithmetic("Multiply"), |
105 | | Arithmetic("Divide"), |
106 | | Arithmetic("Remainder"), |
107 | | |
108 | | // Comparators result in booleans and are treated as INTEGERs. |
109 | | OpComparator("Not"), |
110 | | OpComparator("IsNull"), |
111 | | OpComparator("NotNull"), |
112 | | OpComparator("Ne"), |
113 | | OpComparator("Eq"), |
114 | | OpComparator("Gt"), |
115 | | OpComparator("Le"), |
116 | | OpComparator("Lt"), |
117 | | OpComparator("Ge"), |
118 | | OpComparator("IfNeg"), |
119 | | OpComparator("IfNotZero"), |
120 | | }; |
121 | | |
122 | | RecursiveMutex SQLiteDBInstance::kPrimaryAttachMutex; |
123 | | |
124 | | /// The SQLiteSQLPlugin implements the "sql" registry for internal/core. |
125 | | class SQLiteSQLPlugin : public SQLPlugin { |
126 | | public: |
127 | | /// Execute SQL and store results. |
128 | | Status query(const std::string& query, |
129 | | QueryData& results, |
130 | | bool use_cache) const override; |
131 | | |
132 | | /// Introspect, explain, the suspected types selected in an SQL statement. |
133 | | Status getQueryColumns(const std::string& query, |
134 | | TableColumns& columns) const override; |
135 | | |
136 | | /// Similar to getQueryColumns but return the scanned tables. |
137 | | Status getQueryTables(const std::string& query, |
138 | | std::vector<std::string>& tables) const override; |
139 | | |
140 | | /// Create a SQLite module and attach (CREATE). |
141 | | Status attach(const std::string& name) override; |
142 | | |
143 | | /// Detach a virtual table (DROP). |
144 | | Status detach(const std::string& name) override; |
145 | | }; |
146 | | |
147 | | /// SQL provider for osquery internal/core. |
148 | | REGISTER_INTERNAL(SQLiteSQLPlugin, "sql", "sql"); |
149 | | |
150 | 1.33k | std::string getStringForSQLiteReturnCode(int code) { |
151 | 1.33k | if (kSQLiteReturnCodes.find(code) != kSQLiteReturnCodes.end()) { |
152 | 1.33k | return kSQLiteReturnCodes.at(code); |
153 | 1.33k | } else { |
154 | 0 | std::ostringstream s; |
155 | 0 | s << "Error: " << code << " is not a valid SQLite result code"; |
156 | 0 | return s.str(); |
157 | 0 | } |
158 | 1.33k | } |
159 | | |
160 | | Status SQLiteSQLPlugin::query(const std::string& query, |
161 | | QueryData& results, |
162 | 8.39k | bool use_cache) const { |
163 | 8.39k | auto dbc = SQLiteDBManager::get(); |
164 | 8.39k | dbc->useCache(use_cache); |
165 | 8.39k | auto result = queryInternal(query, results, dbc); |
166 | 8.39k | dbc->clearAffectedTables(); |
167 | 8.39k | return result; |
168 | 8.39k | } |
169 | | |
170 | | Status SQLiteSQLPlugin::getQueryColumns(const std::string& query, |
171 | 0 | TableColumns& columns) const { |
172 | 0 | auto dbc = SQLiteDBManager::get(); |
173 | 0 | return getQueryColumnsInternal(query, columns, dbc); |
174 | 0 | } |
175 | | |
176 | | Status SQLiteSQLPlugin::getQueryTables(const std::string& query, |
177 | 0 | std::vector<std::string>& tables) const { |
178 | 0 | auto dbc = SQLiteDBManager::get(); |
179 | 0 | QueryPlanner planner(query, dbc); |
180 | 0 | tables = planner.tables(); |
181 | 0 | return Status(0); |
182 | 0 | } |
183 | | |
184 | 0 | SQLInternal::SQLInternal(const std::string& query, bool use_cache) { |
185 | 0 | auto dbc = SQLiteDBManager::get(); |
186 | 0 | dbc->useCache(use_cache); |
187 | 0 | status_ = queryInternal(query, resultsTyped_, dbc); |
188 | | |
189 | | // One of the advantages of using SQLInternal (aside from the Registry-bypass) |
190 | | // is the ability to "deep-inspect" the table attributes and actions. |
191 | 0 | event_based_ = (dbc->getAttributes() & TableAttributes::EVENT_BASED) != 0; |
192 | |
|
193 | 0 | dbc->clearAffectedTables(); |
194 | 0 | } |
195 | | |
196 | 0 | QueryDataTyped& SQLInternal::rowsTyped() { |
197 | 0 | return resultsTyped_; |
198 | 0 | } |
199 | | |
200 | 0 | const Status& SQLInternal::getStatus() const { |
201 | 0 | return status_; |
202 | 0 | } |
203 | | |
204 | 0 | bool SQLInternal::eventBased() const { |
205 | 0 | return event_based_; |
206 | 0 | } |
207 | | |
208 | | // Temporary: I'm going to move this from sql.cpp to here in change immediately |
209 | | // following since this is the only place we actually use it (breaking up to |
210 | | // make CRs smaller) |
211 | | extern void escapeNonPrintableBytesEx(std::string& str); |
212 | | |
213 | | class StringEscaperVisitor : public boost::static_visitor<> { |
214 | | public: |
215 | 0 | void operator()(long long& i) const { // NO-OP |
216 | 0 | } |
217 | | |
218 | 0 | void operator()(double& d) const { // NO-OP |
219 | 0 | } |
220 | | |
221 | 0 | void operator()(std::string& str) const { |
222 | 0 | escapeNonPrintableBytesEx(str); |
223 | 0 | } |
224 | | }; |
225 | | |
226 | | class SizeVisitor : public boost::static_visitor<> { |
227 | | public: |
228 | 0 | void operator()(const long long& i) { |
229 | 0 | size = sizeof(i); |
230 | 0 | } |
231 | | |
232 | 0 | void operator()(const double& d) { |
233 | 0 | size = sizeof(d); |
234 | 0 | } |
235 | | |
236 | 0 | void operator()(const std::string& t) { |
237 | 0 | size = t.length(); |
238 | 0 | } |
239 | | |
240 | 0 | uint64_t get_size() const { |
241 | 0 | return size; |
242 | 0 | } |
243 | | |
244 | | private: |
245 | | uint64_t size{0}; |
246 | | }; |
247 | | |
248 | 0 | void SQLInternal::escapeResults() { |
249 | 0 | StringEscaperVisitor visitor; |
250 | 0 | for (auto& rowTyped : resultsTyped_) { |
251 | 0 | for (auto& column : rowTyped) { |
252 | 0 | boost::apply_visitor(visitor, column.second); |
253 | 0 | } |
254 | 0 | } |
255 | 0 | } |
256 | | |
257 | 0 | uint64_t SQLInternal::getSize() { |
258 | 0 | SizeVisitor visitor; |
259 | 0 | uint64_t size = 0; |
260 | 0 | for (const auto& row : rowsTyped()) { |
261 | 0 | for (const auto& column : row) { |
262 | 0 | size += column.first.size(); |
263 | 0 | boost::apply_visitor(visitor, column.second); |
264 | 0 | size += visitor.get_size(); |
265 | 0 | } |
266 | 0 | } |
267 | 0 | return size; |
268 | 0 | } |
269 | | |
270 | 612 | Status SQLiteSQLPlugin::attach(const std::string& name) { |
271 | 612 | PluginResponse response; |
272 | 612 | auto status = |
273 | 612 | Registry::call("table", name, {{"action", "columns"}}, response); |
274 | 612 | if (!status.ok()) { |
275 | 0 | return status; |
276 | 0 | } |
277 | | |
278 | 612 | bool is_extension = true; |
279 | | |
280 | | // Attach requests occurring via the plugin/registry APIs must act on the |
281 | | // primary database. To allow this, getConnection can explicitly request the |
282 | | // primary instance and avoid the contention decisions. |
283 | 612 | auto dbc = SQLiteDBManager::getConnection(true); |
284 | | |
285 | | // Attach as an extension, allowing read/write tables |
286 | 612 | return attachTableInternal(name, dbc, is_extension); |
287 | 612 | } |
288 | | |
289 | 0 | Status SQLiteSQLPlugin::detach(const std::string& name) { |
290 | | // Detach requests occurring via the plugin/registry APIs must act on the |
291 | | // primary database. To allow this, getConnection can explicitly request the |
292 | | // primary instance and avoid the contention decisions. |
293 | 0 | auto dbc = SQLiteDBManager::getConnection(true); |
294 | 0 | return detachTableInternal(name, dbc); |
295 | 0 | } |
296 | | |
297 | | SQLiteDBInstance::SQLiteDBInstance(sqlite3*& db, Mutex& mtx) |
298 | 8.40k | : db_(db), lock_(mtx, boost::try_to_lock) { |
299 | 8.40k | if (lock_.owns_lock()) { |
300 | 8.40k | primary_ = true; |
301 | 8.40k | } else { |
302 | 0 | db_ = nullptr; |
303 | 0 | VLOG(1) << "DBManager contention: opening transient SQLite database"; |
304 | 0 | init(); |
305 | 0 | } |
306 | 8.40k | } |
307 | | |
308 | | // This function is called by SQLite when a statement is prepared and we use |
309 | | // it to allowlist specific actions. |
310 | | int sqliteAuthorizer(void* userData, |
311 | | int code, |
312 | | const char* arg3, |
313 | | const char* arg4, |
314 | | const char* arg5, |
315 | 311k | const char* arg6) { |
316 | 311k | if (kAllowedSQLiteActionCodes.count(code) > 0) { |
317 | 311k | return SQLITE_OK; |
318 | 311k | } |
319 | | |
320 | | // For PRAGMA check the name of the PRAGMA being called. |
321 | 238 | if (code == SQLITE_PRAGMA && arg3 != nullptr) { |
322 | 53 | std::string pragma = arg3; |
323 | 53 | std::transform(pragma.begin(), pragma.end(), pragma.begin(), ::tolower); |
324 | 53 | if (kAllowedSQLitePragmas.count(pragma) > 0) { |
325 | 0 | return SQLITE_OK; |
326 | 0 | } |
327 | 53 | } |
328 | | |
329 | 238 | LOG(ERROR) << "Authorizer denied action " << code << " " |
330 | 238 | << (arg3 ? arg3 : "null") << " " << (arg4 ? arg4 : "null") << " " |
331 | 238 | << (arg5 ? arg5 : "null") << " " << (arg6 ? arg6 : "null"); |
332 | 238 | return SQLITE_DENY; |
333 | 238 | } |
334 | | |
335 | 4 | static inline void openOptimized(sqlite3*& db) { |
336 | 4 | sqlite3_open(":memory:", &db); |
337 | | |
338 | 4 | std::string settings; |
339 | 28 | for (const auto& setting : kMemoryDBSettings) { |
340 | 28 | settings += "PRAGMA " + setting.first + "=" + setting.second + "; "; |
341 | 28 | } |
342 | 4 | sqlite3_exec(db, settings.c_str(), nullptr, nullptr, nullptr); |
343 | | |
344 | | // Register versioning collations and function. |
345 | 4 | registerVersionExtensions(db); |
346 | | |
347 | | // Register function extensions. |
348 | 4 | registerMathExtensions(db); |
349 | 4 | #if !defined(FREEBSD) |
350 | 4 | registerStringExtensions(db); |
351 | 4 | #endif |
352 | 4 | #if !defined(SKIP_CARVER) |
353 | 4 | registerOperationExtensions(db); |
354 | 4 | #endif |
355 | 4 | registerFilesystemExtensions(db); |
356 | 4 | registerHashingExtensions(db); |
357 | 4 | registerEncodingExtensions(db); |
358 | 4 | registerNetworkExtensions(db); |
359 | | |
360 | 4 | auto rc = sqlite3_set_authorizer(db, &sqliteAuthorizer, nullptr); |
361 | 4 | if (rc != SQLITE_OK) { |
362 | 0 | LOG(ERROR) << "Failed to set sqlite authorizer: " << sqlite3_errmsg(db); |
363 | 0 | requestShutdown(rc); |
364 | 0 | } |
365 | 4 | } |
366 | | |
367 | 0 | void SQLiteDBInstance::init() { |
368 | 0 | primary_ = false; |
369 | 0 | openOptimized(db_); |
370 | 0 | } |
371 | | |
372 | 8.39k | void SQLiteDBInstance::useCache(bool use_cache) { |
373 | 8.39k | use_cache_ = use_cache; |
374 | 8.39k | } |
375 | | |
376 | 1.02M | bool SQLiteDBInstance::useCache() const { |
377 | 1.02M | return use_cache_; |
378 | 1.02M | } |
379 | | |
380 | 27.8k | RecursiveLock SQLiteDBInstance::attachLock() const { |
381 | 27.8k | if (isPrimary()) { |
382 | 27.8k | return RecursiveLock(kPrimaryAttachMutex); |
383 | 27.8k | } |
384 | 0 | return RecursiveLock(attach_mutex_); |
385 | 27.8k | } |
386 | | |
387 | | void SQLiteDBInstance::addAffectedTable( |
388 | 1.07M | std::shared_ptr<VirtualTableContent> table) { |
389 | | // An xFilter/scan was requested for this virtual table. |
390 | 1.07M | affected_tables_.insert(std::make_pair(table->name, std::move(table))); |
391 | 1.07M | } |
392 | | |
393 | 0 | bool SQLiteDBInstance::tableCalled(VirtualTableContent const& table) { |
394 | 0 | return (affected_tables_.count(table.name) > 0); |
395 | 0 | } |
396 | | |
397 | 0 | TableAttributes SQLiteDBInstance::getAttributes() const { |
398 | 0 | const SQLiteDBInstance* rdbc = this; |
399 | 0 | if (isPrimary() && !managed_) { |
400 | | // Similarly to clearAffectedTables, the connection may be forwarded. |
401 | 0 | rdbc = SQLiteDBManager::getConnection(true).get(); |
402 | 0 | } |
403 | |
|
404 | 0 | TableAttributes attributes = TableAttributes::NONE; |
405 | 0 | for (const auto& table : rdbc->affected_tables_) { |
406 | 0 | attributes = table.second->attributes | attributes; |
407 | 0 | } |
408 | 0 | return attributes; |
409 | 0 | } |
410 | | |
411 | 16.7k | void SQLiteDBInstance::clearAffectedTables() { |
412 | 16.7k | if (isPrimary() && !managed_) { |
413 | | // A primary instance must forward clear requests to the DB manager's |
414 | | // 'connection' instance. This is a temporary primary instance. |
415 | 8.39k | SQLiteDBManager::getConnection(true)->clearAffectedTables(); |
416 | 8.39k | return; |
417 | 8.39k | } |
418 | | |
419 | 8.39k | for (const auto& table : affected_tables_) { |
420 | 2.69k | table.second->constraints.clear(); |
421 | 2.69k | table.second->cache.clear(); |
422 | 2.69k | table.second->colsUsed.clear(); |
423 | 2.69k | table.second->colsUsedBitsets.clear(); |
424 | 2.69k | } |
425 | | // Since the affected tables are cleared, there are no more affected tables. |
426 | | // There is no concept of compounding tables between queries. |
427 | 8.39k | affected_tables_.clear(); |
428 | 8.39k | use_cache_ = false; |
429 | 8.39k | } |
430 | | |
431 | 8.40k | SQLiteDBInstance::~SQLiteDBInstance() { |
432 | 8.40k | if (!isPrimary() && db_ != nullptr) { |
433 | 0 | sqlite3_close(db_); |
434 | 8.40k | } else { |
435 | 8.40k | db_ = nullptr; |
436 | 8.40k | } |
437 | 8.40k | } |
438 | | |
439 | 4 | SQLiteDBManager::SQLiteDBManager() : db_(nullptr) { |
440 | 4 | sqlite3_soft_heap_limit64(1); |
441 | 4 | setDisabledTables(Flag::getValue("disable_tables")); |
442 | 4 | setEnabledTables(Flag::getValue("enable_tables")); |
443 | 4 | } |
444 | | |
445 | 1.21k | bool SQLiteDBManager::isDisabled(const std::string& table_name) { |
446 | 1.21k | bool disabled_set = !Flag::isDefault("disable_tables"); |
447 | 1.21k | bool enabled_set = !Flag::isDefault("enable_tables"); |
448 | 1.21k | if (!disabled_set && !enabled_set) { |
449 | | // We have zero enabled tables and zero disabled tables. |
450 | | // As a result, no tables are disabled. |
451 | 0 | return false; |
452 | 0 | } |
453 | 1.21k | const auto& element_disabled = instance().disabled_tables_.find(table_name); |
454 | 1.21k | const auto& element_enabled = instance().enabled_tables_.find(table_name); |
455 | 1.21k | bool table_disabled = (element_disabled != instance().disabled_tables_.end()); |
456 | 1.21k | bool table_enabled = (element_enabled != instance().enabled_tables_.end()); |
457 | | |
458 | 1.21k | if (table_disabled) { |
459 | 12 | return true; |
460 | 12 | } |
461 | | |
462 | 1.20k | if (table_enabled && disabled_set && !table_disabled) { |
463 | 0 | return false; |
464 | 0 | } |
465 | | |
466 | 1.20k | if (table_enabled && !disabled_set) { |
467 | 0 | return false; |
468 | 0 | } |
469 | | |
470 | 1.20k | if (enabled_set && !table_enabled) { |
471 | 0 | return true; |
472 | 0 | } |
473 | | |
474 | 1.20k | if (disabled_set && !table_disabled) { |
475 | 1.20k | return false; |
476 | 1.20k | } |
477 | | |
478 | 0 | return true; |
479 | 1.20k | } |
480 | | |
481 | 0 | void SQLiteDBManager::resetPrimary() { |
482 | 0 | auto& self = instance(); |
483 | |
|
484 | 0 | WriteLock connection_lock(self.mutex_); |
485 | 0 | self.connection_.reset(); |
486 | |
|
487 | 0 | { |
488 | 0 | WriteLock create_lock(self.create_mutex_); |
489 | 0 | sqlite3_close(self.db_); |
490 | 0 | self.db_ = nullptr; |
491 | 0 | } |
492 | 0 | } |
493 | | |
494 | 4 | void SQLiteDBManager::setDisabledTables(const std::string& list) { |
495 | 4 | const auto& tables = split(list, ","); |
496 | 4 | disabled_tables_ = |
497 | 4 | std::unordered_set<std::string>(tables.begin(), tables.end()); |
498 | 4 | } |
499 | | |
500 | 4 | void SQLiteDBManager::setEnabledTables(const std::string& list) { |
501 | 4 | const auto& tables = split(list, ","); |
502 | 4 | enabled_tables_ = |
503 | 4 | std::unordered_set<std::string>(tables.begin(), tables.end()); |
504 | 4 | } |
505 | | |
506 | 0 | SQLiteDBInstanceRef SQLiteDBManager::getUnique() { |
507 | 0 | auto instance = std::make_shared<SQLiteDBInstance>(); |
508 | 0 | attachVirtualTables(instance); |
509 | 0 | return instance; |
510 | 0 | } |
511 | | |
512 | 17.4k | SQLiteDBInstanceRef SQLiteDBManager::getConnection(bool primary) { |
513 | 17.4k | auto& self = instance(); |
514 | 17.4k | WriteLock lock(self.create_mutex_); |
515 | | |
516 | 17.4k | if (self.db_ == nullptr) { |
517 | | // Create primary SQLite DB instance. |
518 | 4 | openOptimized(self.db_); |
519 | 4 | self.connection_ = SQLiteDBInstanceRef(new SQLiteDBInstance(self.db_)); |
520 | 4 | attachVirtualTables(self.connection_); |
521 | 4 | } |
522 | | |
523 | | // Internal usage may request the primary connection explicitly. |
524 | 17.4k | if (primary) { |
525 | 9.00k | return self.connection_; |
526 | 9.00k | } |
527 | | |
528 | | // Create a 'database connection' for the managed database instance. |
529 | 8.40k | auto instance = std::make_shared<SQLiteDBInstance>(self.db_, self.mutex_); |
530 | 8.40k | if (!instance->isPrimary()) { |
531 | 0 | attachVirtualTables(instance); |
532 | 0 | } |
533 | | |
534 | 8.40k | return instance; |
535 | 17.4k | } |
536 | | |
537 | 4 | SQLiteDBManager::~SQLiteDBManager() { |
538 | 4 | connection_ = nullptr; |
539 | 4 | if (db_ != nullptr) { |
540 | 4 | sqlite3_close(db_); |
541 | 4 | db_ = nullptr; |
542 | 4 | } |
543 | 4 | } |
544 | | |
545 | | QueryPlanner::QueryPlanner(const std::string& query, |
546 | 0 | const SQLiteDBInstanceRef& instance) { |
547 | 0 | QueryData plan; |
548 | 0 | queryInternal("EXPLAIN QUERY PLAN " + query, plan, instance); |
549 | 0 | queryInternal("EXPLAIN " + query, program_, instance); |
550 | |
|
551 | 0 | for (const auto& row : plan) { |
552 | 0 | auto details = osquery::split(row.at("detail")); |
553 | 0 | if (details.size() > 1 && details[0] == "SCAN") { |
554 | 0 | tables_.push_back(details[1]); |
555 | 0 | } |
556 | 0 | } |
557 | |
|
558 | 0 | instance->clearAffectedTables(); |
559 | 0 | } |
560 | | |
561 | 0 | Status QueryPlanner::applyTypes(TableColumns& columns) { |
562 | 0 | std::map<size_t, ColumnType> column_types; |
563 | 0 | for (const auto& row : program_) { |
564 | 0 | if (row.at("opcode") == "ResultRow") { |
565 | | // The column parsing is finished. |
566 | 0 | auto k = boost::lexical_cast<size_t>(row.at("p1")); |
567 | 0 | for (const auto& type : column_types) { |
568 | 0 | if (type.first - k < columns.size()) { |
569 | 0 | std::get<1>(columns[type.first - k]) = type.second; |
570 | 0 | } |
571 | 0 | } |
572 | 0 | } |
573 | |
|
574 | 0 | if (row.at("opcode") == "Copy") { |
575 | | // Copy P1 -> P1 + P3 into P2 -> P2 + P3. |
576 | 0 | auto from = boost::lexical_cast<size_t>(row.at("p1")); |
577 | 0 | auto to = boost::lexical_cast<size_t>(row.at("p2")); |
578 | 0 | auto size = boost::lexical_cast<size_t>(row.at("p3")); |
579 | 0 | for (size_t i = 0; i <= size; i++) { |
580 | 0 | if (column_types.count(from + i)) { |
581 | 0 | column_types[to + i] = std::move(column_types[from + i]); |
582 | 0 | column_types.erase(from + i); |
583 | 0 | } |
584 | 0 | } |
585 | 0 | } else if (row.at("opcode") == "Cast") { |
586 | 0 | auto value = boost::lexical_cast<size_t>(row.at("p1")); |
587 | 0 | auto to = boost::lexical_cast<size_t>(row.at("p2")); |
588 | 0 | switch (to) { |
589 | 0 | case 'A': // BLOB |
590 | 0 | column_types[value] = BLOB_TYPE; |
591 | 0 | break; |
592 | 0 | case 'B': // TEXT |
593 | 0 | column_types[value] = TEXT_TYPE; |
594 | 0 | break; |
595 | 0 | case 'C': // NUMERIC |
596 | | // We don't exactly have an equivalent to NUMERIC (which includes such |
597 | | // things as DATETIME and DECIMAL |
598 | 0 | column_types[value] = UNKNOWN_TYPE; |
599 | 0 | break; |
600 | 0 | case 'D': // INTEGER |
601 | 0 | column_types[value] = BIGINT_TYPE; |
602 | 0 | break; |
603 | 0 | case 'E': // REAL |
604 | 0 | column_types[value] = DOUBLE_TYPE; |
605 | 0 | break; |
606 | 0 | default: |
607 | 0 | column_types[value] = UNKNOWN_TYPE; |
608 | 0 | break; |
609 | 0 | } |
610 | 0 | } |
611 | | |
612 | 0 | if (kSQLOpcodes.count(row.at("opcode"))) { |
613 | 0 | const auto& op = kSQLOpcodes.at(row.at("opcode")); |
614 | 0 | auto k = boost::lexical_cast<size_t>(row.at(Opcode::regString(op.reg))); |
615 | 0 | column_types[k] = op.type; |
616 | 0 | } |
617 | 0 | } |
618 | | |
619 | 0 | return Status(0); |
620 | 0 | } |
621 | | |
622 | | // Wrapper for legacy method until all uses can be replaced |
623 | | Status queryInternal(const std::string& query, |
624 | | QueryData& results, |
625 | 8.39k | const SQLiteDBInstanceRef& instance) { |
626 | 8.39k | QueryDataTyped typedResults; |
627 | 8.39k | Status status = queryInternal(query, typedResults, instance); |
628 | 8.39k | if (status.ok()) { |
629 | 4.55k | results.reserve(typedResults.size()); |
630 | 31.0M | for (const auto& row : typedResults) { |
631 | 31.0M | Row r; |
632 | 36.2M | for (const auto& col : row) { |
633 | 36.2M | r[col.first] = castVariant(col.second); |
634 | 36.2M | } |
635 | 31.0M | results.push_back(std::move(r)); |
636 | 31.0M | } |
637 | 4.55k | } |
638 | 8.39k | return status; |
639 | 8.39k | } |
640 | | |
641 | | Status readRows(sqlite3_stmt* prepared_statement, |
642 | | QueryDataTyped& results, |
643 | 23.6k | const SQLiteDBInstanceRef& instance) { |
644 | | // Do nothing with a null prepared_statement (eg, if the sql was just |
645 | | // whitespace) |
646 | 23.6k | if (prepared_statement == nullptr) { |
647 | 32 | return Status::success(); |
648 | 32 | } |
649 | 23.5k | int rc = sqlite3_step(prepared_statement); |
650 | | /* if we have a result set row... */ |
651 | 23.5k | if (SQLITE_ROW == rc) { |
652 | | // First collect the column names |
653 | 18.5k | int num_columns = sqlite3_column_count(prepared_statement); |
654 | 18.5k | std::vector<std::string> colNames; |
655 | 18.5k | colNames.reserve(num_columns); |
656 | 121k | for (int i = 0; i < num_columns; i++) { |
657 | 103k | colNames.push_back(sqlite3_column_name(prepared_statement, i)); |
658 | 103k | } |
659 | | |
660 | 31.8M | do { |
661 | 31.8M | RowTyped row; |
662 | 74.6M | for (int i = 0; i < num_columns; i++) { |
663 | 42.8M | switch (sqlite3_column_type(prepared_statement, i)) { |
664 | 12.0M | case SQLITE_INTEGER: |
665 | 12.0M | row[colNames[i]] = static_cast<long long>( |
666 | 12.0M | sqlite3_column_int64(prepared_statement, i)); |
667 | 12.0M | break; |
668 | 104k | case SQLITE_FLOAT: |
669 | 104k | row[colNames[i]] = sqlite3_column_double(prepared_statement, i); |
670 | 104k | break; |
671 | 25.6M | case SQLITE_NULL: |
672 | 25.6M | row[colNames[i]] = FLAGS_nullvalue; |
673 | 25.6M | break; |
674 | 5.06M | default: |
675 | | // Everything else (SQLITE_TEXT, SQLITE3_TEXT, SQLITE_BLOB) is |
676 | | // obtained/conveyed as text/string |
677 | 5.06M | row[colNames[i]] = std::string(reinterpret_cast<const char*>( |
678 | 5.06M | sqlite3_column_text(prepared_statement, i))); |
679 | 42.8M | } |
680 | 42.8M | } |
681 | 31.8M | results.push_back(std::move(row)); |
682 | 31.8M | rc = sqlite3_step(prepared_statement); |
683 | 31.8M | } while (SQLITE_ROW == rc); |
684 | 18.5k | } |
685 | 23.5k | if (rc != SQLITE_DONE) { |
686 | 812 | auto s = Status::failure(sqlite3_errmsg(instance->db())); |
687 | 812 | sqlite3_finalize(prepared_statement); |
688 | 812 | return s; |
689 | 812 | } |
690 | | |
691 | 22.7k | rc = sqlite3_finalize(prepared_statement); |
692 | 22.7k | if (rc != SQLITE_OK) { |
693 | 0 | return Status::failure(sqlite3_errmsg(instance->db())); |
694 | 0 | } |
695 | | |
696 | 22.7k | return Status::success(); |
697 | 22.7k | } |
698 | | |
699 | | Status queryInternal(const std::string& query, |
700 | | QueryDataTyped& results, |
701 | 8.39k | const SQLiteDBInstanceRef& instance) { |
702 | 8.39k | sqlite3_stmt* prepared_statement{nullptr}; /* Statement to execute. */ |
703 | | |
704 | 8.39k | int rc = SQLITE_OK; /* Return Code */ |
705 | 8.39k | const char* leftover_sql = nullptr; /* Tail of unprocessed SQL */ |
706 | 8.39k | const char* sql = query.c_str(); /* SQL to be processed */ |
707 | | |
708 | | /* The big while loop. One iteration per statement */ |
709 | 31.1k | while ((sql[0] != '\0') && (SQLITE_OK == rc)) { |
710 | 26.6k | const auto lock = instance->attachLock(); |
711 | | |
712 | | // Trim leading whitespace |
713 | 29.3k | while (isspace(sql[0])) { |
714 | 2.72k | sql++; |
715 | 2.72k | } |
716 | 26.6k | rc = sqlite3_prepare_v2( |
717 | 26.6k | instance->db(), sql, -1, &prepared_statement, &leftover_sql); |
718 | 26.6k | if (rc != SQLITE_OK) { |
719 | 3.02k | Status s = Status::failure(sqlite3_errmsg(instance->db())); |
720 | 3.02k | sqlite3_finalize(prepared_statement); |
721 | 3.02k | return s; |
722 | 3.02k | } |
723 | | |
724 | 23.6k | Status s = readRows(prepared_statement, results, instance); |
725 | 23.6k | if (!s.ok()) { |
726 | 812 | return s; |
727 | 812 | } |
728 | | |
729 | 22.8k | sql = leftover_sql; |
730 | 22.8k | } /* end while */ |
731 | 4.55k | sqlite3_db_release_memory(instance->db()); |
732 | 4.55k | return Status::success(); |
733 | 8.39k | } |
734 | | |
735 | | Status getQueryColumnsInternal(const std::string& q, |
736 | | TableColumns& columns, |
737 | 0 | const SQLiteDBInstanceRef& instance) { |
738 | 0 | Status status = Status(); |
739 | 0 | TableColumns results; |
740 | 0 | { |
741 | 0 | auto lock = instance->attachLock(); |
742 | | |
743 | | // Turn the query into a prepared statement |
744 | 0 | sqlite3_stmt* stmt{nullptr}; |
745 | 0 | auto rc = sqlite3_prepare_v2(instance->db(), |
746 | 0 | q.c_str(), |
747 | 0 | static_cast<int>(q.length() + 1), |
748 | 0 | &stmt, |
749 | 0 | nullptr); |
750 | 0 | if (rc != SQLITE_OK || stmt == nullptr) { |
751 | 0 | auto s = Status::failure(sqlite3_errmsg(instance->db())); |
752 | 0 | if (stmt != nullptr) { |
753 | 0 | sqlite3_finalize(stmt); |
754 | 0 | } |
755 | 0 | return s; |
756 | 0 | } |
757 | | |
758 | | // Get column count |
759 | 0 | auto num_columns = sqlite3_column_count(stmt); |
760 | 0 | results.reserve(num_columns); |
761 | | |
762 | | // Get column names and types |
763 | 0 | bool unknown_type = false; |
764 | 0 | for (int i = 0; i < num_columns; ++i) { |
765 | 0 | auto col_name = sqlite3_column_name(stmt, i); |
766 | 0 | auto col_type = sqlite3_column_decltype(stmt, i); |
767 | |
|
768 | 0 | if (col_name == nullptr) { |
769 | 0 | status = Status(1, "Could not get column type"); |
770 | 0 | break; |
771 | 0 | } |
772 | | |
773 | 0 | if (col_type == nullptr) { |
774 | | // Types are only returned for table columns (not expressions). |
775 | 0 | col_type = "UNKNOWN"; |
776 | 0 | unknown_type = true; |
777 | 0 | } |
778 | 0 | results.push_back(std::make_tuple( |
779 | 0 | col_name, columnTypeName(col_type), ColumnOptions::DEFAULT)); |
780 | 0 | } |
781 | | |
782 | | // An unknown type means we have to parse the plan and SQLite opcodes. |
783 | 0 | if (unknown_type) { |
784 | 0 | QueryPlanner planner(q, instance); |
785 | 0 | planner.applyTypes(results); |
786 | 0 | } |
787 | 0 | sqlite3_finalize(stmt); |
788 | 0 | } |
789 | | |
790 | 0 | if (status.ok()) { |
791 | 0 | columns = std::move(results); |
792 | 0 | } |
793 | |
|
794 | 0 | return status; |
795 | 0 | } |
796 | | } // namespace osquery |