int internal_eqvp(CELL obj1, CELL obj2) { if (AS_LITERAL(obj1) == AS_LITERAL(obj2)) { return 1; } if (! (IS_POINTER(obj1) && IS_POINTER(obj2)) ) { return 0; } TYPEID t = GET_POINTER_TYPE(obj1); if (t != GET_POINTER_TYPE(obj2)) { return 0; } switch(t) { case T_FLOAT: return GET_FLOAT(obj1) == GET_FLOAT(obj2); case T_BIGINT: return GET_BIGINT(obj1) == GET_BIGINT(obj2); default: return 0; } //FIXME - does not implement equality correctly for LAMBDAs //principally because LAMBDAs are not implemented correctly //yet either (i.e. as closures). }
bool ConstraintList::literal_matches(const T& base_expr) const { bool aggregate = true; for (size_t i = 0; i < constraints_.size(); ++i) { T constraint_expr = AS_LITERAL(T, constraints_[i].expr); if (constraints_[i].op == EQUALS) { aggregate = aggregate && (base_expr == constraint_expr); } else if (constraints_[i].op == GREATER_THAN) { aggregate = aggregate && (base_expr > constraint_expr); } else if (constraints_[i].op == LESS_THAN) { aggregate = aggregate && (base_expr < constraint_expr); } else if (constraints_[i].op == GREATER_THAN_OR_EQUALS) { aggregate = aggregate && (base_expr >= constraint_expr); } else if (constraints_[i].op == LESS_THAN_OR_EQUALS) { aggregate = aggregate && (base_expr <= constraint_expr); } else { // Unsupported constraint. return false; } if (!aggregate) { // Speed up comparison. return false; } } return true; }
int internal_eqp(CELL obj1, CELL obj2) { if (AS_LITERAL(obj1) == AS_LITERAL(obj2)) { return 1; } if (! (IS_POINTER(obj1) && IS_POINTER(obj2)) ) { return 0; } TYPEID t = GET_POINTER_TYPE(obj1); if (t != GET_POINTER_TYPE(obj2)) { return 0; } return 0; }
bool ConstraintList::matches(const std::string& expr) const { // Support each SQL affinity type casting. if (affinity == TEXT_TYPE) { return literal_matches<TEXT_LITERAL>(expr); } else if (affinity == INTEGER_TYPE) { INTEGER_LITERAL lexpr = AS_LITERAL(INTEGER_LITERAL, expr); return literal_matches<INTEGER_LITERAL>(lexpr); } else if (affinity == BIGINT_TYPE) { BIGINT_LITERAL lexpr = AS_LITERAL(BIGINT_LITERAL, expr); return literal_matches<BIGINT_LITERAL>(lexpr); } else if (affinity == UNSIGNED_BIGINT_TYPE) { UNSIGNED_BIGINT_LITERAL lexpr = AS_LITERAL(UNSIGNED_BIGINT_LITERAL, expr); return literal_matches<UNSIGNED_BIGINT_LITERAL>(lexpr); } else { // Unsupported affinity type. return false; } }
SimpleProcStat getProcStat(const std::string& pid) { SimpleProcStat stat; std::string content; if (readFile(getProcAttr("stat", pid), content).ok()) { auto detail_start = content.find_last_of(")"); // Start parsing stats from ") <MODE>..." auto details = osquery::split(content.substr(detail_start + 2), " "); stat.state = details.at(0); stat.parent = details.at(1); stat.group = details.at(2); stat.user_time = details.at(11); stat.system_time = details.at(12); stat.nice = details.at(16); stat.start_time = TEXT(AS_LITERAL(BIGINT_LITERAL, details.at(19)) / 100); } if (readFile(getProcAttr("status", pid), content).ok()) { for (const auto& line : osquery::split(content, "\n")) { // Status lines are formatted: Key: Value....\n. auto detail = osquery::split(line, ":", 1); if (detail.size() != 2) { continue; } // There are specific fields from each detail. if (detail.at(0) == "Name") { stat.name = detail.at(1); } else if (detail.at(0) == "VmRSS") { detail[1].erase(detail.at(1).end() - 3, detail.at(1).end()); // Memory is reported in kB. stat.resident_size = detail.at(1) + "000"; } else if (detail.at(0) == "VmSize") { detail[1].erase(detail.at(1).end() - 3, detail.at(1).end()); // Memory is reported in kB. stat.phys_footprint = detail.at(1) + "000"; } else if (detail.at(0) == "Gid") { // Format is: R E - - auto gid_detail = osquery::split(detail.at(1), "\t"); if (gid_detail.size() == 4) { stat.real_gid = gid_detail.at(0); stat.effective_gid = gid_detail.at(1); } } else if (detail.at(0) == "Uid") { auto uid_detail = osquery::split(detail.at(1), "\t"); if (uid_detail.size() == 4) { stat.real_uid = uid_detail.at(0); stat.effective_uid = uid_detail.at(1); } } } } return stat; }
void Config::recordQueryPerformance(const std::string& name, size_t delay, size_t size, const Row& r0, const Row& r1) { RecursiveLock lock(config_performance_mutex_); if (performance_.count(name) == 0) { performance_[name] = QueryPerformance(); } // Grab access to the non-const schedule item. auto& query = performance_.at(name); BIGINT_LITERAL diff = 0; if (!r1.at("user_time").empty() && !r0.at("user_time").empty()) { diff = AS_LITERAL(BIGINT_LITERAL, r1.at("user_time")) - AS_LITERAL(BIGINT_LITERAL, r0.at("user_time")); if (diff > 0) { query.user_time += diff; } } if (!r1.at("system_time").empty() && !r0.at("system_time").empty()) { diff = AS_LITERAL(BIGINT_LITERAL, r1.at("system_time")) - AS_LITERAL(BIGINT_LITERAL, r0.at("system_time")); if (diff > 0) { query.system_time += diff; } } if (!r1.at("resident_size").empty() && !r0.at("resident_size").empty()) { diff = AS_LITERAL(BIGINT_LITERAL, r1.at("resident_size")) - AS_LITERAL(BIGINT_LITERAL, r0.at("resident_size")); if (diff > 0) { // Memory is stored as an average of RSS changes between query executions. query.average_memory = (query.average_memory * query.executions) + diff; query.average_memory = (query.average_memory / (query.executions + 1)); } } query.wall_time += delay; query.output_size += size; query.executions += 1; query.last_executed = getUnixTime(); // Clear the executing query (remove the dirty bit). setDatabaseValue(kPersistentSettings, kExecutingQuery, ""); }
void Config::recordQueryPerformance(const std::string& name, size_t delay, size_t size, const Row& r0, const Row& r1) { // Grab a lock on the schedule structure and check the name. ConfigDataInstance config; if (config.schedule().count(name) == 0) { // Unknown query schedule name. return; } // Grab access to the non-const schedule item. auto& query = getInstance().data_.schedule.at(name); auto diff = AS_LITERAL(BIGINT_LITERAL, r1.at("user_time")) - AS_LITERAL(BIGINT_LITERAL, r0.at("user_time")); if (diff > 0) { query.user_time += diff; } diff = AS_LITERAL(BIGINT_LITERAL, r1.at("system_time")) - AS_LITERAL(BIGINT_LITERAL, r0.at("system_time")); if (diff > 0) { query.system_time += diff; } diff = AS_LITERAL(BIGINT_LITERAL, r1.at("resident_size")) - AS_LITERAL(BIGINT_LITERAL, r0.at("resident_size")); if (diff > 0) { // Memory is stored as an average of RSS changes between query executions. query.average_memory = (query.average_memory * query.executions) + diff; query.average_memory = (query.average_memory / (query.executions + 1)); } query.wall_time += delay; query.output_size += size; query.executions += 1; }
int internal_equalp(CELL obj1, CELL obj2) { while(1) { if (AS_LITERAL(obj1) == AS_LITERAL(obj2)) { return 1; } if (! (IS_POINTER(obj1) && IS_POINTER(obj2)) ) { return 0; } if (GET_POINTER_TYPE(obj1) != GET_POINTER_TYPE(obj2)) { return 0; } switch(GET_POINTER_TYPE(obj1)) { case T_CONS: // FIXME - unbounded recursion! if (!internal_equalp(CAR(obj1), CAR(obj2))) { return 0; } obj1 = CDR(obj1); obj2 = CDR(obj2); break; case T_VECTOR: case T_RECORD: { VECTOR * const vec1 = GET_VECTOR(obj1); VECTOR * const vec2 = GET_VECTOR(obj2); if (vec1->len != vec2->len) { return 0; } int i; for(i = 0; i < vec1->len; ++i) { // FIXME - unbounded recursion! if (!internal_equalp(vec1->data[i], vec2->data[i])) { return 0; } } return 1; } case T_STRING: { STRING * const p1 = GET_STRING(obj1); STRING * const p2 = GET_STRING(obj2); return p1->len == p2->len && 0 == memcmp(p1->data, p2->data, p1->len); } case T_FLOAT: return GET_FLOAT(obj1) == GET_FLOAT(obj2); case T_BIGINT: return GET_BIGINT(obj1) == GET_BIGINT(obj2); default: return 0; } } }
bool WatcherRunner::isChildSane(const PlatformProcess& child) const { auto rows = SQL::selectAllFrom("processes", "pid", EQUALS, INTEGER(child.pid())); if (rows.size() == 0) { // Could not find worker process? return false; } // Get the performance state for the worker or extension. size_t sustained_latency = 0; // Compare CPU utilization since last check. size_t footprint = 0; pid_t parent = 0; // IV is the check interval in seconds, and utilization is set per-second. auto iv = std::max(getWorkerLimit(INTERVAL), (size_t)1); { WatcherLocker locker; auto& state = Watcher::getState(child); UNSIGNED_BIGINT_LITERAL user_time = 0, system_time = 0; try { parent = AS_LITERAL(BIGINT_LITERAL, rows[0].at("parent")); user_time = AS_LITERAL(BIGINT_LITERAL, rows[0].at("user_time")) / iv; system_time = AS_LITERAL(BIGINT_LITERAL, rows[0].at("system_time")) / iv; footprint = AS_LITERAL(BIGINT_LITERAL, rows[0].at("resident_size")); } catch (const std::exception& e) { state.sustained_latency = 0; } // Check the difference of CPU time used since last check. if (user_time - state.user_time > getWorkerLimit(UTILIZATION_LIMIT) || system_time - state.system_time > getWorkerLimit(UTILIZATION_LIMIT)) { state.sustained_latency++; } else { state.sustained_latency = 0; } // Update the current CPU time. state.user_time = user_time; state.system_time = system_time; // Check if the sustained difference exceeded the acceptable latency limit. sustained_latency = state.sustained_latency; // Set the memory footprint as the amount of resident bytes allocated // since the process image was created (estimate). // A more-meaningful check would limit this to writable regions. if (state.initial_footprint == 0) { state.initial_footprint = footprint; } // Set the measured/limit-applied footprint to the post-launch allocations. if (footprint < state.initial_footprint) { footprint = 0; } else { footprint = footprint - state.initial_footprint; } } // Only make a decision about the child sanity if it is still the watcher's // child. It's possible for the child to die, and its pid reused. if (parent != PlatformProcess::getCurrentProcess()->pid()) { // The child's parent is not the watcher. Watcher::reset(child); // Do not stop or call the child insane, since it is not our child. return true; } if (sustained_latency > 0 && sustained_latency * iv >= getWorkerLimit(LATENCY_LIMIT)) { LOG(WARNING) << "osqueryd worker (" << child.pid() << ") system performance limits exceeded"; return false; } // Check if the private memory exceeds a memory limit. if (footprint > 0 && footprint > getWorkerLimit(MEMORY_LIMIT) * 1024 * 1024) { LOG(WARNING) << "osqueryd worker (" << child.pid() << ") memory limits exceeded: " << footprint; return false; } // The worker is sane, no action needed. // Attempt to flush status logs to the well-behaved worker. if (use_worker_) { relayStatusLogs(); } return true; }
void internal_generic_output(FILE* fp, CELL cell, int strict, int tab) { switch(GET_TYPE(cell)) { case T_VOID: fputs("#<void>", fp); break; case T_NULL: fputs("()", fp); break; case T_UNDEFINED: fputs("#<undefined>", fp); break; case T_EMPTY: fputs("#<empty>", fp); break; case T_BOOL: fputs(GET_BOOL(cell) ? "#t" : "#f", fp); break; case T_CHAR: { CHAR ch = GET_CHAR(cell); if (strict) { switch(ch) { case ' ': fputs("#\\space", fp); break; case 0: fputs("#\\nul", fp); break; case 27: fputs("#\\escape", fp); break; case 127: fputs("#\\rubout", fp); break; case '\a': fputs("#\\alarm", fp); break; case '\b': fputs("#\\backspace", fp); break; case '\f': fputs("#\\page", fp); break; case '\n': fputs("#\\newline", fp); break; case '\r': fputs("#\\return", fp); break; case '\t': fputs("#\\tab", fp); break; case '\v': fputs("#\\vtab", fp); break; default: fprintf(fp, "#\\%c", ch); break; } } else { fputc(ch, fp); } } break; case T_INT: fprintf(fp, "%d", GET_INT(cell)); break; case T_BIGINT: fprintf(fp, "%lld", GET_BIGINT(cell)); break; case T_FLOAT: fprintf(fp, "%f", GET_FLOAT(cell)); break; case T_STRING: { STRING* p = GET_STRING(cell); size_t len = p->len; char* data = p->data; if (strict) { // FIXME -- make this more efficient, and escape other special chars? fputc('"', fp); while(len--) { char ch = *data++; if (ch == '"' || ch == '\\') { fputc('\\', fp); } fputc(ch, fp); } fputc('"', fp); } else { fwrite(data, 1, len, fp); } } break; case T_NAME: { NAME* p = GET_NAME(cell); if (p->gensym) { fprintf(fp, "#_%d", p->gensym); } else { fwrite(GET_NAME(cell)->data, 1, GET_NAME(cell)->len, fp); } } break; case T_KEYWORD: { KEYWORD* p = GET_KEYWORD(cell); fwrite(p->data, 1, p->len, fp); fputc(':', fp); } break; case T_SLOT: fprintf(fp, "#<slot:%d>", GET_SLOT(cell)); break; // FIXME - arbitrary recursion case T_CONS: fputc('(', fp); if (tab) ++tab; int did = 0; while(1) { int pair = CONSP(CAR(cell)); if (!did && tab && pair && !CONSP(CAR(CAR(cell)))) { fprintf(fp, "\n%*s", (tab-1)*2, ""); } internal_generic_output(fp, CAR(cell), strict, tab); cell = CDR(cell); if (NULLP(cell)) { break; } did = (tab && pair); if (did) { fprintf(fp, "\n%*s", (tab-1)*2, ""); } else fputc(' ', fp); if (!CONSP(cell)) { fputs(". ", fp); internal_generic_output(fp, cell, strict, tab); break; } } fputc(')', fp); break; // FIXME - arbitrary recursion case T_VECTOR: { VECTOR *vec = GET_VECTOR(cell); fputs("#(", fp); if (vec->len > 0) { int i = 0; internal_generic_output(fp, vec->data[i++], strict, tab); while(i < vec->len) { fputc(' ', fp); internal_generic_output(fp, vec->data[i++], strict, tab); } } fputc(')', fp); break; } case T_FUNC: fprintf(fp, "#<primitive:%s>", GET_FUNC(cell)->name); break; case T_COMPILED_LAMBDA: fprintf(fp, "#<compiled-lambda:0x%08x>", AS_LITERAL(cell)); break; { if (tab) ++tab; COMPILED_LAMBDA *l = GET_COMPILED_LAMBDA(cell); fprintf(fp, "#<%s %d%s:%d/%d", l->is_macro ? "macro" : "lambda", l->argc, l->rest ? "+" : "", l->depth, l->max_slot); if (tab) { fprintf(fp, "\n%*s", (tab-1)*2, ""); } else { fputc(' ', fp); } internal_generic_output(fp, l->body, strict, tab); fputc('>', fp); } break; case T_CLOSURE: fprintf(fp, "#<closure:0x%08x>", AS_LITERAL(cell)); break; { if (tab) ++tab; CLOSURE *c = GET_CLOSURE(cell); fprintf(fp, "#<closure "); if (tab) { fprintf(fp, "\n%*s", (tab-1)*2, ""); } internal_print_env(fp, c->env); if (tab) { fprintf(fp, "\n%*s", (tab-1)*2, ""); } fputc(' ', fp); internal_generic_output(fp, c->compiled_lambda, strict, tab); fputc('>', fp); } break; case T_EXCEPTION: fputs("#<exception:", fp); fwrite(GET_EXCEPTION(cell)->data, 1, GET_EXCEPTION(cell)->len, fp); fputc('>', fp); break; case T_REIFIED_CONTINUATION: fprintf(fp, "#<continuation:0x%08x>", (int)GET_REIFIED_CONTINUATION(cell)->cont); break; case T_STACK_FRAME: { STACK_FRAME* p = GET_STACK_FRAME(cell); fputs("#<stack-frame [", fp); int i; for(i = 0; i < p->len; ++i) { if (i) fputc(' ', fp); fprintf(fp, "0x%08x", (int)p->cells[i]); } fputs("]>", fp); } break; case T_ENV: fprintf(fp, "#<env:count=%d>", GET_ENV(cell)->count); break; case T_RELOC: fprintf(fp, "#<reloc:0x%08x>", (int)GET_RELOC(cell)); break; case T_PORT: fprintf(fp, "#<port:%s>", GET_PORT(cell)->data); break; case T_DB_CONNECTION: fprintf(fp, "#<db-connection>"); break; case T_DB_RESULT: fprintf(fp, "#<db-result>"); break; case T_RECORD: fprintf(fp, "#<record>"); break; default: fprintf(fp, "#<%s-%02x:%08x>", IS_LITERAL(cell) ? "literal" : "pointer", GET_TYPE(cell), AS_LITERAL(cell) ); break; } }