Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Event scope escape #733

Merged
merged 9 commits into from
Feb 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 5 additions & 12 deletions userspace/libsinsp/docker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,14 +340,10 @@ void docker::handle_event(Json::Value&& root)
{
image = img.asString();
}
std::string scope("host.mac=");
event_scope scope;
if(m_machine_id.length())
{
scope.append(m_machine_id);
}
else
{
scope.clear();
scope.add("host.mac", m_machine_id);
}
if(is_image_event(event_name))
{
Expand All @@ -359,13 +355,11 @@ void docker::handle_event(Json::Value&& root)
}
if(!id.empty())
{
if(scope.length()) { scope.append(" and "); }
scope.append("container.image=").append(id);
scope.add("container.image", id);
}
else if(!image.empty())
{
if(scope.length()) { scope.append(" and "); }
scope.append("container.image=").append(image);
scope.add("container.image", image);
}
else
{
Expand All @@ -377,8 +371,7 @@ void docker::handle_event(Json::Value&& root)
{
if(id.length() >= 12)
{
if(scope.length()) { scope.append(" and "); }
scope.append("container.id=").append(id.substr(0, 12));
scope.add("container.id", id.substr(0, 12));
}
}
if(status.length())
Expand Down
44 changes: 25 additions & 19 deletions userspace/libsinsp/k8s_component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ bool k8s_event_t::update(const Json::Value& item, k8s_state_t& state)
std::string event_name;
std::string description;
severity_t severity = sinsp_logger::SEV_EVT_INFORMATION;
std::string scope;
event_scope scope;
tag_map_t tags;

const Json::Value& obj = item["involvedObject"];
Expand Down Expand Up @@ -875,26 +875,34 @@ bool k8s_event_t::update(const Json::Value& item, k8s_state_t& state)
const k8s_component* comp = state.get_component(component_uid, &t);
if(comp && !t.empty())
{
std::string node_name = comp->get_node_name();
const std::string& node_name = comp->get_node_name();
if(!node_name.empty())
{
if(scope.length()) { scope.append(" and "); }
scope.append("kubernetes.node.name=").append(node_name);
scope.add("kubernetes.node.name", node_name);
}
const std::string& ns = comp->get_namespace();
if(!ns.empty())
{
if(scope.length()) { scope.append(" and "); }
scope.append("kubernetes.namespace.name=").append(ns);
scope.add("kubernetes.namespace.name", ns);
}
const std::string& comp_name = comp->get_name();
if(comp_name.empty())
{
scope.add(std::string("kubernetes.").append(t).append(".name"), comp_name);
}
if(scope.length()) { scope.append(" and "); }
scope.append("kubernetes.").append(t).append(".name=").append(comp->get_name());
/* no labels for now
for(const auto& label : comp->get_labels())
{
tags[label.first] = label.second;
g_logger.log("EVENT label: [" + label.first + ':' + label.second + ']', sinsp_logger::SEV_DEBUG);
scope.append(" and kubernetes.").append(t).append(".label.").append(label.first).append(1, '=').append(label.second);
//g_logger.log("EVENT label: [" + label.first + ':' + label.second + ']', sinsp_logger::SEV_DEBUG);
if(event_scope::check(label.second))
{
scope.append(" and kubernetes.").append(t).append(".label.").append(label.first).append(1, '=').append(label.second);
}
else
{
g_logger.log("K8s invalid scope entry: [" + label.second + ']', sinsp_logger::SEV_WARNING);
}
}*/
}
else if(epoch_time_now_s < (epoch_time_evt_s + 120))
Expand Down Expand Up @@ -922,33 +930,31 @@ bool k8s_event_t::update(const Json::Value& item, k8s_state_t& state)

tags["source"] = "kubernetes";
g_logger.log(sinsp_user_event::to_string(epoch_time_evt_s, std::move(event_name), std::move(description),
std::move(scope), std::move(tags)), severity);
std::move(scope), std::move(tags)), severity);

// TODO: sysdig capture?
#endif // _WIN32

return true;
}

void k8s_event_t::make_scope_impl(const Json::Value& obj, std::string comp, std::string& scope, bool ns)
void k8s_event_t::make_scope_impl(const Json::Value& obj, std::string comp, event_scope& scope, bool ns)
{
if(ns)
{
std::string ns_name = get_json_string(obj, "namespace");
const std::string& ns_name = get_json_string(obj, "namespace");
if(!ns_name.empty())
{
if(scope.length()) { scope.append(" and "); }
scope.append("kubernetes.namespace.name=").append(ns_name);
scope.add("kubernetes.namespace.name", ns_name);
}
}
if(comp.length() && ci_compare::is_equal(get_json_string(obj, "kind"), comp))
{
std::string comp_name = get_json_string(obj, "name");
const std::string& comp_name = get_json_string(obj, "name");
if(!comp_name.empty())
{
if(scope.length()) { scope.append(" and "); }
comp[0] = tolower(comp[0]);
scope.append("kubernetes.").append(comp).append(".name=").append(comp_name);
scope.add(std::string("kubernetes.").append(comp).append(".name"), comp_name);
}
if(comp_name.empty())
{
Expand All @@ -961,7 +967,7 @@ void k8s_event_t::make_scope_impl(const Json::Value& obj, std::string comp, std:
}
}

void k8s_event_t::make_scope(const Json::Value& obj, std::string& scope)
void k8s_event_t::make_scope(const Json::Value& obj, event_scope& scope)
{
if(ci_compare::is_equal(get_json_string(obj, "kind"), "Pod"))
{
Expand Down
5 changes: 3 additions & 2 deletions userspace/libsinsp/k8s_component.h
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ class k8s_deployment_t : public k8s_component
//

class k8s_state_t;
class event_scope;

class k8s_event_t : public k8s_component
{
Expand All @@ -522,8 +523,8 @@ class k8s_event_t : public k8s_component
typedef sinsp_logger::event_severity severity_t;
typedef std::unordered_map<std::string, std::string> name_translation_map_t;

void make_scope(const Json::Value& obj, std::string& scope);
void make_scope_impl(const Json::Value& obj, std::string comp, std::string& scope, bool ns = true);
void make_scope(const Json::Value& obj, event_scope& scope);
void make_scope_impl(const Json::Value& obj, std::string comp, event_scope& scope, bool ns = true);

name_translation_map_t m_name_translation;
std::map<std::string, Json::Value> m_postponed_events;
Expand Down
112 changes: 110 additions & 2 deletions userspace/libsinsp/user_event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,114 @@ along with sysdig. If not, see <http://www.gnu.org/licenses/>.
#include "sinsp_int.h"
#include "user_event.h"

//
// event_scope
//

const std::string event_scope::SCOPE_OP_AND = "and";

// these string lists contain reserved strings; some of the reserved
// strings are escaped and mandatory to be first in RESERVED_STRINGS
// and have their escaped counterparts in the REPLACEMENT_STRINGS,
// in the same order as they appear in RESERVED_STRINGS
const event_scope::string_list_t event_scope::RESERVED_STRINGS =
{"'"};
const event_scope::string_list_t event_scope::REPLACEMENT_STRINGS =
{"\\'"};

// scope key name format regex
const std::string event_scope::KEY_FORMAT = "[a-zA-Z0-9_/\\.-]*";

event_scope::event_scope(const std::string& key, const std::string& value)
{
add(key, value, "");
}

bool event_scope::add(const std::string& key, const std::string& value, const std::string& op)
{
if(check_key_format(key))
{
std::string k(key);
std::string o(!m_scope.empty() ? op : "");
std::string v(value);
replace(v);
if(!v.empty())
{
if(!o.empty())
{
m_scope.append(1, ' ').append(trim(o)).append(1, ' ');
}
m_scope.append(trim(k)).append("='").append(trim(v)).append(1, 0x27);
return true;
}
}
else
{
g_logger.log("Scope key is invalid: [" + key + "], entry will not be added to scope.",
sinsp_logger::SEV_WARNING);
}
return false;
}

string& event_scope::replace(std::string& value)
{
ASSERT(RESERVED_STRINGS.size() == REPLACEMENT_STRINGS.size());

string_list_t::const_iterator res_it = RESERVED_STRINGS.cbegin();
string_list_t::const_iterator res_end = RESERVED_STRINGS.cend();
string_list_t::const_iterator rep_it = REPLACEMENT_STRINGS.cbegin();
string_list_t::const_iterator rep_end = REPLACEMENT_STRINGS.cend();
for(; res_it != res_end && rep_it != rep_end; ++res_it, ++rep_it)
{
replace_in_place(value, *res_it, *rep_it);
}

return value;
}

void event_scope::regex_error(const std::string& call, size_t ret, regex_t* preg, const std::string& str)
{
if(!preg) { return; }
char errbuf[256] = {0};
if(regerror(ret, preg, errbuf, 256))
{
g_logger.log(call + "() error: " + errbuf, sinsp_logger::SEV_WARNING);
}
else
{
g_logger.log("Can't obtain " + call + "() [" + str + "] error.", sinsp_logger::SEV_WARNING);
}
}

bool event_scope::check_key_format(const std::string& key)
{
if(key.empty()) { return false; }
bool result = false;
std::string exp(KEY_FORMAT);
regex_t reg = {0};
size_t ret = regcomp(&reg, exp.c_str(), REG_EXTENDED);
if(0 == ret)
{
regmatch_t rm = {0};
ret = regexec(&reg, key.c_str(), 1, &rm, 0);
if(0 == ret)
{
if((rm.rm_eo - rm.rm_so) == static_cast<regoff_t>(key.length()))
{
result = true;
}
}
else { regex_error("regexec", ret, &reg, key); }
}
else { regex_error("regcomp", ret, &reg, exp); }
regfree(&reg);
return result;
}


//
// user_event_meta_t
//
const std::string user_event_meta_t::PERMIT_ALL = "all";

user_event_meta_t::user_event_meta_t(const std::string& kind, const type_list_t& types):
Expand Down Expand Up @@ -266,7 +374,7 @@ sinsp_user_event& sinsp_user_event::operator=(sinsp_user_event&& other)
std::string sinsp_user_event::to_string(uint64_t timestamp,
std::string&& name,
std::string&& description,
std::string&& scope,
event_scope&& scope,
tag_map_t&& tags,
uint32_t sev)
{
Expand All @@ -277,7 +385,7 @@ std::string sinsp_user_event::to_string(uint64_t timestamp,
ostr << "timestamp: " << timestamp << '\n' <<
"name: \"" << replace_in_place(name, from, to) << "\"\n"
"description: \"" << replace_in_place(description, from, to) << "\"\n"
"scope: \"" << replace_in_place(scope, from, to) << "\"\n";
"scope: \"" << replace_in_place(scope.get_ref(), from, to) << "\"\n";

if(sev != UNKNOWN_SEVERITY)
{
Expand Down
56 changes: 55 additions & 1 deletion userspace/libsinsp/user_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,60 @@ along with sysdig. If not, see <http://www.gnu.org/licenses/>.
#include <string>
#include <set>
#include <unordered_map>
#include <regex.h>

//
// scope utilities
//
class event_scope
{
public:
typedef std::vector<std::string> string_list_t;

static const std::string SCOPE_OP_AND;
static const string_list_t RESERVED_STRINGS;
static const string_list_t REPLACEMENT_STRINGS;
static const std::string KEY_FORMAT;

event_scope(const std::string& key = "", const std::string& value = "");

bool add(const std::string& key, const std::string& value, const std::string& op = SCOPE_OP_AND);

const std::string& get() const;
std::string& get_ref();

void clear();

// utility function to check that a scope entry key is valid;
// valid entries match KEY_FORMAT regular expression
static bool check_key_format(const std::string& key);

private:

// utility function to replace RESERVED_STRINGS with their
// counterparts in REPLACEMENT_STRINGS
static string& replace(std::string& scope);

static void regex_error(const std::string& call, size_t ret, regex_t* preg, const std::string& str);

std::string m_scope;
};

inline const std::string& event_scope::get() const
{
return m_scope;
}

inline std::string& event_scope::get_ref()
{
return m_scope;
}

inline void event_scope::clear()
{
m_scope.clear();
}


//
// user-configured event meta
Expand Down Expand Up @@ -207,7 +261,7 @@ class sinsp_user_event
static std::string to_string(uint64_t timestamp,
std::string&& name,
std::string&& description,
std::string&& scope,
event_scope&& scope,
tag_map_t&& tags,
uint32_t sev = UNKNOWN_SEVERITY);

Expand Down