Merge pull request #383 from theopolis/fix_rpm_packages

[Fix #367] Check RPMTAG class before cast
This commit is contained in:
Teddy Reed 2014-11-10 01:59:13 -08:00
commit bc05f5de78
8 changed files with 135 additions and 40 deletions

View File

@ -13,6 +13,9 @@ else()
endif()
set(OS_COMPILE_FLAGS "-std=c++11")
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
set(OS_COMPILE_FLAGS "${OS_COMPILE_FLAGS} -g")
endif()
set(OS_WHOLELINK_PRE "-Wl,-whole-archive")
set(OS_WHOLELINK_POST "-Wl,-no-whole-archive")
endif()

View File

@ -11,7 +11,8 @@ else
endif
all: .setup
cd build/$(BUILD_DIR) && cmake ../.. && make --no-print-directory $(MAKEFLAGS)
cd build/$(BUILD_DIR) && cmake -DCMAKE_BUILD_TYPE= ../.. && \
make --no-print-directory $(MAKEFLAGS)
debug: .setup
cd build/$(BUILD_DIR) && cmake -DCMAKE_BUILD_TYPE=Debug ../../ && \

View File

@ -12,9 +12,9 @@
#include <boost/thread/locks.hpp>
#include <boost/thread/mutex.hpp>
#include "osquery/status.h"
#include "osquery/database.h"
#include "osquery/registry.h"
#include "osquery/status.h"
namespace osquery {

View File

@ -4361,10 +4361,6 @@ int launchIntoShell(int argc, char **argv) {
return rc;
}
}
} else {
fprintf(stderr, "%s: Error: unknown option: %s\n", Argv0, z);
fprintf(stderr, "Use -help for a list of options.\n");
return 1;
}
}
@ -4431,7 +4427,10 @@ int launchIntoShell(int argc, char **argv) {
sqlite3_close(data.db);
}
sqlite3_free(data.zFreeOnClose);
free(data.prettyPrint);
if (data.prettyPrint != nullptr) {
delete data.prettyPrint;
}
return rc;
}
}

View File

@ -9,10 +9,16 @@
#include "osquery/core.h"
#include "osquery/core/conversions.h"
#include "osquery/events.h"
#include "osquery/flags.h"
#include "osquery/dispatcher.h"
namespace osquery {
DEFINE_osquery_flag(bool,
event_pubsub,
true,
"Use (enable) the osquery eventing pub/sub.")
const std::vector<size_t> kEventTimeLists = {
1 * 60, // 1 minute
1 * 60 * 60, // 1 hour
@ -375,6 +381,10 @@ Status EventFactory::deregisterEventPublishers() {
namespace osquery {
namespace registries {
void faucet(EventPublishers ets, EventSubscribers ems) {
if (!FLAGS_event_pubsub) {
// Invocation disabled eventing.
return;
}
auto& ef = osquery::EventFactory::getInstance();
for (const auto& event_pub : ets) {
ef.registerEventPublisher(event_pub.second);

View File

@ -5,9 +5,7 @@ schema([
Column(name="release", type="std::string"),
Column(name="source", type="std::string"),
Column(name="size", type="std::string"),
Column(name="dsaheader", type="std::string"),
Column(name="rsaheader", type="std::string"),
Column(name="sha1header", type="std::string"),
Column(name="sha1", type="std::string"),
Column(name="arch", type="std::string"),
])
implementation("system/rpm_packages@genRpms")

View File

@ -12,56 +12,84 @@
#include <boost/lexical_cast.hpp>
#include "osquery/logger.h"
#include "osquery/database.h"
namespace osquery {
namespace tables {
/**
* @brief Return a string representation of the RPM tag type.
*
* @param header A librpm header.
* @param tag A librpm rpmTag_t name.
* @param td A librpm rpmtd.
*
* Given a librpm iterator header and a requested tag name:
* 1. Determine the type of the tag (the class of value).
* 2. Request a const pointer or cast of numerate to that class.
* 3. Lexical-cast the value for SQL.
*
* @return The string representation of the tag type.
*/
std::string getRpmAttribute(const Header& header, rpmTag tag, const rpmtd& td) {
std::string result;
if (headerGet(header, tag, td, HEADERGET_DEFAULT) == 0) {
// Intentional check for a 0 = failure.
VLOG(3) << "Could not get RPM header flag.";
return result;
}
if (rpmTagGetClass(tag) == RPM_NUMERIC_CLASS) {
long long int attr = rpmtdGetNumber(td);
result = boost::lexical_cast<std::string>(attr);
} else if (rpmTagGetClass(tag) == RPM_STRING_CLASS) {
const char* attr = rpmtdGetString(td);
if (attr != nullptr) {
result = std::string(attr);
}
}
return result;
}
QueryData genRpms() {
QueryData results;
// The following implementation uses http://rpm.org/api/4.11.1/
Header header;
rpmdbMatchIterator match_iterator;
rpmReadConfigFiles(NULL, NULL);
rpmInitCrypto();
if (rpmReadConfigFiles(nullptr, nullptr) != 0) {
LOG(ERROR) << "Cannot read RPM configuration files.";
return results;
}
rpmts ts = rpmtsCreate();
match_iterator = rpmtsInitIterator(ts, RPMTAG_NAME, NULL, 0);
while ((header = rpmdbNextIterator(match_iterator)) != NULL) {
Row r;
rpmtd td = rpmtdNew();
r["name"] = getRpmAttribute(header, RPMTAG_NAME, td);
r["version"] = getRpmAttribute(header, RPMTAG_VERSION, td);
r["release"] = getRpmAttribute(header, RPMTAG_RELEASE, td);
r["source"] = getRpmAttribute(header, RPMTAG_SOURCERPM, td);
r["size"] = getRpmAttribute(header, RPMTAG_SIZE, td);
r["sha1"] = getRpmAttribute(header, RPMTAG_SHA1HEADER, td);
r["arch"] = getRpmAttribute(header, RPMTAG_ARCH, td);
headerGet(header, RPMTAG_NAME, td, HEADERGET_DEFAULT);
r["name"] = std::string(rpmtdGetString(td));
headerGet(header, RPMTAG_VERSION, td, HEADERGET_DEFAULT);
r["version"] = std::string(rpmtdGetString(td));
headerGet(header, RPMTAG_RELEASE, td, HEADERGET_DEFAULT);
r["release"] = std::string(rpmtdGetString(td));
headerGet(header, RPMTAG_SOURCERPM, td, HEADERGET_DEFAULT);
r["source"] = std::string(rpmtdGetString(td));
headerGet(header, RPMTAG_SIZE, td, HEADERGET_DEFAULT);
r["size"] = std::string(rpmtdGetString(td));
headerGet(header, RPMTAG_DSAHEADER, td, HEADERGET_DEFAULT);
r["dsaheader"] = std::string(rpmtdGetString(td));
headerGet(header, RPMTAG_RSAHEADER, td, HEADERGET_DEFAULT);
r["rsaheader"] = std::string(rpmtdGetString(td));
headerGet(header, RPMTAG_SHA1HEADER, td, HEADERGET_DEFAULT);
r["sha1header"] = std::string(rpmtdGetString(td));
headerGet(header, RPMTAG_ARCH, td, HEADERGET_DEFAULT);
r["arch"] = std::string(rpmtdGetString(td));
rpmtdFree(td);
results.push_back(r);
}
rpmdbFreeIterator(match_iterator);
rpmtsFree(ts);
rpmFreeCrypto();
rpmFreeRpmrc();
return results;
}
}

View File

@ -6,7 +6,13 @@ from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import argparse
try:
import argparse
except ImportError:
print ("Cannot import argparse.")
print ("Try: sudo yum install python-argparse")
exit(1)
import json
import os
import psutil
@ -54,7 +60,9 @@ def queries_from_tables(path, restrict):
tables.append("%s.%s" % (spec_platform, table_name))
tables = [t for t in tables if t not in restrict_tables]
queries = {t: "SELECT * FROM %s;" % t.split(".", 1)[1] for t in tables}
queries = {}
for table in tables:
queries[table] = "SELECT * FROM %s;" % table.split(".", 1)[1]
return queries
def get_stats(p, interval=1):
@ -68,6 +76,45 @@ def get_stats(p, interval=1):
"memory": p.memory_info_ex(),
}
def check_leaks(shell, query, supp_file=None):
"""Run valgrind using the shell and a query, parse leak reports."""
start_time = time.time()
suppressions = "" if supp_file is None else "--suppressions=%s" % supp_file
cmd = "valgrind --tool=memcheck %s %s --query=\"%s\"" % (
suppressions, shell, query)
proc = subprocess.Popen(cmd,
shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
summary = {
"definitely": None,
"indirectly": None,
"possibly": None,
}
for line in stderr.split("\n"):
for key in summary:
if line.find(key) >= 0:
summary[key] = line.split(":")[1].strip()
return summary
def profile_leaks(shell, queries, supp_file=None):
report = {}
for name, query in queries.iteritems():
print ("Analyzing leaks in query: %s" % query)
summary = check_leaks(shell, query, supp_file)
display = []
for key in summary:
output = summary[key]
if output is not None and output[0] != "0":
# Add some fun colored output if leaking.
if key == "definitely":
output = red(output)
if key == "indirectly":
output = yellow(output)
display.append("%s: %s" % (key, output))
print (" %s" % "; ".join(display))
report[name] = summary
return report
def run_query(shell, query, timeout=0, count=1):
"""Execute the osquery run testing wrapper with a setup/teardown delay."""
start_time = time.time()
@ -174,6 +221,10 @@ if __name__ == "__main__":
help="Number of times to run each query.")
parser.add_argument("--rounds", default=1, type=int,
help="Run the profile for multiple rounds and use the average.")
parser.add_argument("--leaks", default=False, action="store_true",
help="Check for memory leaks instead of performance.")
parser.add_argument("--suppressions", default=None,
help="Add a suppressions files to memory leak checking.")
parser.add_argument("--shell",
default="./build/%s/tools/run" % (platform),
help="Path to osquery run wrapper.")
@ -198,6 +249,11 @@ if __name__ == "__main__":
else:
queries = queries_from_tables(args.tables, args.restrict)
if args.leaks:
results = profile_leaks(args.shell, queries,
supp_file=args.suppressions)
exit(0)
# Start the profiling!
results = profile(args.shell, queries,
timeout=args.timeout, count=args.count, rounds=args.rounds)