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 8 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
110 changes: 108 additions & 2 deletions userspace/libsinsp/user_event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,111 @@ 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 =
{"\\'"};

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))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Key can't contain ', it should be in [a-zA-Z\.] format.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not allowing digits?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes allow digits as well

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

slash, dash,...?
eg:
image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{
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(const std::string& scope)
{
if(scope.empty()) { return false; }
bool result = false;
std::string exp("[a-zA-Z0-9_/\\.-]*");
regex_t reg = {0};
size_t ret = regcomp(&reg, exp.c_str(), REG_EXTENDED);
if(0 == ret)
{
regmatch_t rm = {0};
ret = regexec(&reg, scope.c_str(), 1, &rm, 0);
if(0 == ret)
{
if((rm.rm_eo - rm.rm_so) == static_cast<regoff_t>(scope.length()))
{
result = true;
}
}
else { regex_error("regexec", ret, &reg, scope); }
}
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,18 +371,19 @@ 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)
{
const std::string from("\"");
const std::string to("\\\"");

std::string s(scope.get());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This breaks the move optimization by requiring a copy from scope to the local string, but you can avoid the copy by changing get() to return an rvalue reference of event_scope::m_scope.

The rvalue reference version could also use a scarier name than get() so it's clear it's moving the string.

std::ostringstream ostr;
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(s, from, to) << "\"\n";

if(sev != UNKNOWN_SEVERITY)
{
Expand Down
52 changes: 50 additions & 2 deletions userspace/libsinsp/user_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public L nameicense
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix the license notice, looks like an accidental search/replace

along with sysdig. If not, see <http://www.gnu.org/licenses/>.
*/

Expand All @@ -24,6 +24,54 @@ 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;

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);

std::string get();

void clear();

// utility function to check that scope entry is valid;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is out of date, please update it. Also, the name is vague. How about check_key_format()?

// valid entries can not contain characters from RESERVED_STRINGS
// which are not present in REPLACEMENT_STRINGS
static bool check(const std::string& scope);

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 std::string event_scope::get()
{
return m_scope;
}

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


//
// user-configured event meta
Expand Down Expand Up @@ -207,7 +255,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