From eb6cd0ba15ce511dd1f344fa75409d4124410160 Mon Sep 17 00:00:00 2001 From: Alex Fabijanic Date: Fri, 20 Jan 2017 20:58:03 -0600 Subject: [PATCH 1/7] add scope utils and k8s/docker events scope checks --- userspace/libsinsp/docker.cpp | 45 ++++++++++++++--- userspace/libsinsp/k8s_component.cpp | 73 ++++++++++++++++++++++------ userspace/libsinsp/user_event.cpp | 5 ++ userspace/libsinsp/user_event.h | 43 ++++++++++++++++ 4 files changed, 143 insertions(+), 23 deletions(-) diff --git a/userspace/libsinsp/docker.cpp b/userspace/libsinsp/docker.cpp index e4ff07783b..5125e6db91 100644 --- a/userspace/libsinsp/docker.cpp +++ b/userspace/libsinsp/docker.cpp @@ -340,10 +340,17 @@ void docker::handle_event(Json::Value&& root) { image = img.asString(); } - std::string scope("host.mac="); + std::string scope; if(m_machine_id.length()) { - scope.append(m_machine_id); + if(event_scope::check(m_machine_id)) + { + scope.append("host.mac=").append(m_machine_id); + } + else + { + g_logger.log("Docker invalid scope entry for host.mac: [" + m_machine_id + ']', sinsp_logger::SEV_WARNING); + } } else { @@ -359,13 +366,27 @@ void docker::handle_event(Json::Value&& root) } if(!id.empty()) { - if(scope.length()) { scope.append(" and "); } - scope.append("container.image=").append(id); + if(event_scope::check(id)) + { + if(scope.length()) { scope.append(" and "); } + scope.append("container.image=").append(id); + } + else + { + g_logger.log("Docker invalid scope entry for container.image: [" + image + ']', sinsp_logger::SEV_WARNING); + } } else if(!image.empty()) { - if(scope.length()) { scope.append(" and "); } - scope.append("container.image=").append(image); + if(event_scope::check(image)) + { + if(scope.length()) { scope.append(" and "); } + scope.append("container.image=").append(image); + } + else + { + g_logger.log("Docker invalid scope entry for container.image: [" + image + ']', sinsp_logger::SEV_WARNING); + } } else { @@ -377,8 +398,16 @@ 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)); + std::string id12 = id.substr(0, 12); + if(event_scope::check(id12)) + { + if(scope.length()) { scope.append(" and "); } + scope.append("container.id=").append(id12); + } + else + { + g_logger.log("Docker invalid scope entry for container.id: [" + id12 + ']', sinsp_logger::SEV_WARNING); + } } } if(status.length()) diff --git a/userspace/libsinsp/k8s_component.cpp b/userspace/libsinsp/k8s_component.cpp index 968b51e02e..cec3bad44c 100644 --- a/userspace/libsinsp/k8s_component.cpp +++ b/userspace/libsinsp/k8s_component.cpp @@ -875,26 +875,55 @@ 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); + if(event_scope::check(node_name)) + { + if(scope.length()) { scope.append(" and "); } + scope.append("kubernetes.node.name=").append(node_name); + } + else + { + g_logger.log("K8s invalid scope entry for kubernetes.node.name: [" + node_name + ']', sinsp_logger::SEV_WARNING); + } } const std::string& ns = comp->get_namespace(); if(!ns.empty()) + { + if(event_scope::check(ns)) + { + if(scope.length()) { scope.append(" and "); } + scope.append("kubernetes.namespace.name=").append(ns); + } + else + { + g_logger.log("K8s invalid scope entry for kubernetes.namespace.name: [" + ns + ']', sinsp_logger::SEV_WARNING); + } + } + const std::string& comp_name = comp->get_name(); + if(event_scope::check(comp_name)) { if(scope.length()) { scope.append(" and "); } - scope.append("kubernetes.namespace.name=").append(ns); + scope.append("kubernetes.").append(t).append(".name=").append(comp_name); + } + else + { + g_logger.log("K8s invalid scope entry for kubernetes." + t + ".name: [" + comp_name + ']', sinsp_logger::SEV_WARNING); } - 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)) @@ -934,21 +963,35 @@ void k8s_event_t::make_scope_impl(const Json::Value& obj, std::string comp, std: { 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); + if(event_scope::check(ns_name)) + { + if(scope.length()) { scope.append(" and "); } + scope.append("kubernetes.namespace.name=").append(ns_name); + } + else + { + g_logger.log("K8s invalid scope entry for kubernetes.namespace.name: [" + ns_name + ']', sinsp_logger::SEV_WARNING); + } } } 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); + if(event_scope::check(comp_name)) + { + if(scope.length()) { scope.append(" and "); } + comp[0] = tolower(comp[0]); + scope.append("kubernetes.").append(comp).append(".name=").append(comp_name); + } + else + { + g_logger.log("K8s invalid scope entry for kubernetes." + comp_name + ".name: [" + comp_name + ']', sinsp_logger::SEV_WARNING); + } } if(comp_name.empty()) { diff --git a/userspace/libsinsp/user_event.cpp b/userspace/libsinsp/user_event.cpp index ef6734bf4a..312320dd5f 100644 --- a/userspace/libsinsp/user_event.cpp +++ b/userspace/libsinsp/user_event.cpp @@ -20,6 +20,11 @@ along with sysdig. If not, see . #include "sinsp_int.h" #include "user_event.h" +const event_scope::string_list_t event_scope::RESERVED_STRINGS = + {"'"/*!must be first!*/, "=", " and "}; +const event_scope::string_list_t event_scope::REPLACEMENT_STRINGS = + {"\\'", "='", "' and "}; // !do not change order! + 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): diff --git a/userspace/libsinsp/user_event.h b/userspace/libsinsp/user_event.h index 186eab9d02..ffdfe3585a 100644 --- a/userspace/libsinsp/user_event.h +++ b/userspace/libsinsp/user_event.h @@ -25,6 +25,49 @@ along with sysdig. If not, see . #include #include +// +// scope utilities +// +struct event_scope +{ + typedef std::vector string_list_t; + + static const string_list_t RESERVED_STRINGS; + static const string_list_t REPLACEMENT_STRINGS; + + // utility function to escape scope entries and wrap them in single quotes; + // this function is used internally but is left public for testing purposes + static string&& escape(std::string&& scope) + { + trim(scope); + 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(scope, *res_it, *rep_it); + } + scope.append(1, 0x27); // terminating single quote + return std::move(scope); + } + + // utility function to check that scope entry is valid; + // valid entries can not contain '=' character or " and " string + static bool check(const std::string& scope) + { + for(const auto& rs : RESERVED_STRINGS) + { + if(scope.find(rs) != std::string::npos) + { + return false; + } + } + return true; + } +}; + + // // user-configured event meta // From 87f73e4693ec239429214d123900375739436a3f Mon Sep 17 00:00:00 2001 From: Alex Fabijanic Date: Fri, 20 Jan 2017 21:49:55 -0600 Subject: [PATCH 2/7] factor out scope check and assembly --- userspace/libsinsp/docker.cpp | 40 +++------------------- userspace/libsinsp/k8s_component.cpp | 51 ++++------------------------ userspace/libsinsp/user_event.cpp | 46 +++++++++++++++++++++++++ userspace/libsinsp/user_event.h | 34 +++++-------------- 4 files changed, 65 insertions(+), 106 deletions(-) diff --git a/userspace/libsinsp/docker.cpp b/userspace/libsinsp/docker.cpp index 5125e6db91..572c991e95 100644 --- a/userspace/libsinsp/docker.cpp +++ b/userspace/libsinsp/docker.cpp @@ -343,14 +343,7 @@ void docker::handle_event(Json::Value&& root) std::string scope; if(m_machine_id.length()) { - if(event_scope::check(m_machine_id)) - { - scope.append("host.mac=").append(m_machine_id); - } - else - { - g_logger.log("Docker invalid scope entry for host.mac: [" + m_machine_id + ']', sinsp_logger::SEV_WARNING); - } + event_scope::assemble(scope, "host.mac", m_machine_id); } else { @@ -366,27 +359,11 @@ void docker::handle_event(Json::Value&& root) } if(!id.empty()) { - if(event_scope::check(id)) - { - if(scope.length()) { scope.append(" and "); } - scope.append("container.image=").append(id); - } - else - { - g_logger.log("Docker invalid scope entry for container.image: [" + image + ']', sinsp_logger::SEV_WARNING); - } + event_scope::assemble(scope, "container.image", id); } else if(!image.empty()) { - if(event_scope::check(image)) - { - if(scope.length()) { scope.append(" and "); } - scope.append("container.image=").append(image); - } - else - { - g_logger.log("Docker invalid scope entry for container.image: [" + image + ']', sinsp_logger::SEV_WARNING); - } + event_scope::assemble(scope, "container.image", image); } else { @@ -398,16 +375,7 @@ void docker::handle_event(Json::Value&& root) { if(id.length() >= 12) { - std::string id12 = id.substr(0, 12); - if(event_scope::check(id12)) - { - if(scope.length()) { scope.append(" and "); } - scope.append("container.id=").append(id12); - } - else - { - g_logger.log("Docker invalid scope entry for container.id: [" + id12 + ']', sinsp_logger::SEV_WARNING); - } + event_scope::assemble(scope, "container.id", id.substr(0, 12)); } } if(status.length()) diff --git a/userspace/libsinsp/k8s_component.cpp b/userspace/libsinsp/k8s_component.cpp index cec3bad44c..69c6a83e9c 100644 --- a/userspace/libsinsp/k8s_component.cpp +++ b/userspace/libsinsp/k8s_component.cpp @@ -878,38 +878,17 @@ bool k8s_event_t::update(const Json::Value& item, k8s_state_t& state) const std::string& node_name = comp->get_node_name(); if(!node_name.empty()) { - if(event_scope::check(node_name)) - { - if(scope.length()) { scope.append(" and "); } - scope.append("kubernetes.node.name=").append(node_name); - } - else - { - g_logger.log("K8s invalid scope entry for kubernetes.node.name: [" + node_name + ']', sinsp_logger::SEV_WARNING); - } + event_scope::assemble(scope, "kubernetes.node.name", node_name); } const std::string& ns = comp->get_namespace(); if(!ns.empty()) { - if(event_scope::check(ns)) - { - if(scope.length()) { scope.append(" and "); } - scope.append("kubernetes.namespace.name=").append(ns); - } - else - { - g_logger.log("K8s invalid scope entry for kubernetes.namespace.name: [" + ns + ']', sinsp_logger::SEV_WARNING); - } + event_scope::assemble(scope, "kubernetes.namespace.name", ns); } const std::string& comp_name = comp->get_name(); - if(event_scope::check(comp_name)) + if(comp_name.empty()) { - if(scope.length()) { scope.append(" and "); } - scope.append("kubernetes.").append(t).append(".name=").append(comp_name); - } - else - { - g_logger.log("K8s invalid scope entry for kubernetes." + t + ".name: [" + comp_name + ']', sinsp_logger::SEV_WARNING); + event_scope::assemble(scope, std::string("kubernetes.").append(t).append(".name"), comp_name); } /* no labels for now for(const auto& label : comp->get_labels()) @@ -966,15 +945,7 @@ void k8s_event_t::make_scope_impl(const Json::Value& obj, std::string comp, std: const std::string& ns_name = get_json_string(obj, "namespace"); if(!ns_name.empty()) { - if(event_scope::check(ns_name)) - { - if(scope.length()) { scope.append(" and "); } - scope.append("kubernetes.namespace.name=").append(ns_name); - } - else - { - g_logger.log("K8s invalid scope entry for kubernetes.namespace.name: [" + ns_name + ']', sinsp_logger::SEV_WARNING); - } + event_scope::assemble(scope, "kubernetes.namespace.name", ns_name); } } if(comp.length() && ci_compare::is_equal(get_json_string(obj, "kind"), comp)) @@ -982,16 +953,8 @@ void k8s_event_t::make_scope_impl(const Json::Value& obj, std::string comp, std: const std::string& comp_name = get_json_string(obj, "name"); if(!comp_name.empty()) { - if(event_scope::check(comp_name)) - { - if(scope.length()) { scope.append(" and "); } - comp[0] = tolower(comp[0]); - scope.append("kubernetes.").append(comp).append(".name=").append(comp_name); - } - else - { - g_logger.log("K8s invalid scope entry for kubernetes." + comp_name + ".name: [" + comp_name + ']', sinsp_logger::SEV_WARNING); - } + comp[0] = tolower(comp[0]); + event_scope::assemble(scope, std::string("kubernetes.").append(comp).append(".name"), comp_name); } if(comp_name.empty()) { diff --git a/userspace/libsinsp/user_event.cpp b/userspace/libsinsp/user_event.cpp index 312320dd5f..cf6517c372 100644 --- a/userspace/libsinsp/user_event.cpp +++ b/userspace/libsinsp/user_event.cpp @@ -25,6 +25,52 @@ const event_scope::string_list_t event_scope::RESERVED_STRINGS = const event_scope::string_list_t event_scope::REPLACEMENT_STRINGS = {"\\'", "='", "' and "}; // !do not change order! +string&& event_scope::escape(std::string&& scope) +{ + trim(scope); + 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(scope, *res_it, *rep_it); + } + scope.append(1, 0x27); // terminating single quote + return std::move(scope); +} + +// utility function to check that scope entry is valid; +// valid entries can not contain '=' character or " and " string +bool event_scope::check(const std::string& scope) +{ + string_list_t::const_iterator rs = RESERVED_STRINGS.cbegin(); + ++rs; + for(; rs != RESERVED_STRINGS.end(); ++rs) + { + if(scope.find(*rs) != std::string::npos) + { + return false; + } + } + return true; +} + +bool event_scope::assemble(std::string& scope, const std::string& name, const std::string& value) +{ + if(check(name) && check(value)) + { + if(scope.length()) { scope.append(" and "); } + scope.append(name).append(1, '=').append(value); + return true; + } + else + { + g_logger.log("Invalid scope entry for " + name + ": [" + value + ']', sinsp_logger::SEV_WARNING); + } + return false; +} + 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): diff --git a/userspace/libsinsp/user_event.h b/userspace/libsinsp/user_event.h index ffdfe3585a..d957b8c9c3 100644 --- a/userspace/libsinsp/user_event.h +++ b/userspace/libsinsp/user_event.h @@ -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 along with sysdig. If not, see . */ @@ -37,34 +37,16 @@ struct event_scope // utility function to escape scope entries and wrap them in single quotes; // this function is used internally but is left public for testing purposes - static string&& escape(std::string&& scope) - { - trim(scope); - 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(scope, *res_it, *rep_it); - } - scope.append(1, 0x27); // terminating single quote - return std::move(scope); - } + static string&& escape(std::string&& scope); // utility function to check that scope entry is valid; // valid entries can not contain '=' character or " and " string - static bool check(const std::string& scope) - { - for(const auto& rs : RESERVED_STRINGS) - { - if(scope.find(rs) != std::string::npos) - { - return false; - } - } - return true; - } + static bool check(const std::string& scope); + + // utility function to check that scope entry is valid and + // assemble it; returns true if succesful, false otherwise; + // valid entries can not contain '=' character or " and " string + static bool assemble(std::string& scope, const std::string& name, const std::string& value); }; From e340987a1ed0bfb79e23295b445f046e8f5b533c Mon Sep 17 00:00:00 2001 From: Alex Fabijanic Date: Tue, 31 Jan 2017 23:04:23 -0600 Subject: [PATCH 3/7] event scope class --- userspace/libsinsp/docker.cpp | 14 ++-- userspace/libsinsp/k8s_component.cpp | 18 +++--- userspace/libsinsp/k8s_component.h | 5 +- userspace/libsinsp/user_event.cpp | 97 ++++++++++++++++++++-------- userspace/libsinsp/user_event.h | 40 +++++++++--- 5 files changed, 116 insertions(+), 58 deletions(-) diff --git a/userspace/libsinsp/docker.cpp b/userspace/libsinsp/docker.cpp index 572c991e95..6eff7a7ec9 100644 --- a/userspace/libsinsp/docker.cpp +++ b/userspace/libsinsp/docker.cpp @@ -340,14 +340,10 @@ void docker::handle_event(Json::Value&& root) { image = img.asString(); } - std::string scope; + event_scope scope; if(m_machine_id.length()) { - event_scope::assemble(scope, "host.mac", m_machine_id); - } - else - { - scope.clear(); + scope.add("host.mac", m_machine_id); } if(is_image_event(event_name)) { @@ -359,11 +355,11 @@ void docker::handle_event(Json::Value&& root) } if(!id.empty()) { - event_scope::assemble(scope, "container.image", id); + scope.add("container.image", id); } else if(!image.empty()) { - event_scope::assemble(scope, "container.image", image); + scope.add("container.image", image); } else { @@ -375,7 +371,7 @@ void docker::handle_event(Json::Value&& root) { if(id.length() >= 12) { - event_scope::assemble(scope, "container.id", id.substr(0, 12)); + scope.add("container.id", id.substr(0, 12)); } } if(status.length()) diff --git a/userspace/libsinsp/k8s_component.cpp b/userspace/libsinsp/k8s_component.cpp index 69c6a83e9c..19dc5f92f0 100644 --- a/userspace/libsinsp/k8s_component.cpp +++ b/userspace/libsinsp/k8s_component.cpp @@ -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"]; @@ -878,17 +878,17 @@ bool k8s_event_t::update(const Json::Value& item, k8s_state_t& state) const std::string& node_name = comp->get_node_name(); if(!node_name.empty()) { - event_scope::assemble(scope, "kubernetes.node.name", node_name); + scope.add("kubernetes.node.name", node_name); } const std::string& ns = comp->get_namespace(); if(!ns.empty()) { - event_scope::assemble(scope, "kubernetes.namespace.name", ns); + scope.add("kubernetes.namespace.name", ns); } const std::string& comp_name = comp->get_name(); if(comp_name.empty()) { - event_scope::assemble(scope, std::string("kubernetes.").append(t).append(".name"), comp_name); + scope.add(std::string("kubernetes.").append(t).append(".name"), comp_name); } /* no labels for now for(const auto& label : comp->get_labels()) @@ -930,7 +930,7 @@ 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 @@ -938,14 +938,14 @@ bool k8s_event_t::update(const Json::Value& item, k8s_state_t& state) 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) { const std::string& ns_name = get_json_string(obj, "namespace"); if(!ns_name.empty()) { - event_scope::assemble(scope, "kubernetes.namespace.name", ns_name); + scope.add("kubernetes.namespace.name", ns_name); } } if(comp.length() && ci_compare::is_equal(get_json_string(obj, "kind"), comp)) @@ -954,7 +954,7 @@ void k8s_event_t::make_scope_impl(const Json::Value& obj, std::string comp, std: if(!comp_name.empty()) { comp[0] = tolower(comp[0]); - event_scope::assemble(scope, std::string("kubernetes.").append(comp).append(".name"), comp_name); + scope.add(std::string("kubernetes.").append(comp).append(".name"), comp_name); } if(comp_name.empty()) { @@ -967,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")) { diff --git a/userspace/libsinsp/k8s_component.h b/userspace/libsinsp/k8s_component.h index 64c387a546..c7fd4e1617 100644 --- a/userspace/libsinsp/k8s_component.h +++ b/userspace/libsinsp/k8s_component.h @@ -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 { @@ -522,8 +523,8 @@ class k8s_event_t : public k8s_component typedef sinsp_logger::event_severity severity_t; typedef std::unordered_map 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 m_postponed_events; diff --git a/userspace/libsinsp/user_event.cpp b/userspace/libsinsp/user_event.cpp index cf6517c372..84792ebed9 100644 --- a/userspace/libsinsp/user_event.cpp +++ b/userspace/libsinsp/user_event.cpp @@ -20,30 +20,81 @@ along with sysdig. If not, see . #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 = - {"'"/*!must be first!*/, "=", " and "}; + {"'"/*!must be first!*/, "=", " and ", " "}; const event_scope::string_list_t event_scope::REPLACEMENT_STRINGS = - {"\\'", "='", "' and "}; // !do not change order! + {"\\'"/*!must be first!*/}; + +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)) + { + 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 has invalid value: [" + key + "], not added to scope.", sinsp_logger::SEV_WARNING); + } + return false; +} -string&& event_scope::escape(std::string&& scope) +string& event_scope::replace(std::string& value) { - trim(scope); - 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) + ASSERT(RESERVED_STRINGS.size() >= REPLACEMENT_STRINGS.size()); + + if(check(value)) + { + trim(value); + 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) + { + replace_in_place(value, *res_it, *rep_it); + if(++rep_it == rep_end) { break; } + } + } + else { - replace_in_place(scope, *res_it, *rep_it); + g_logger.log("Cannot replace invalid value: [" + value + "], string will be cleared.", sinsp_logger::SEV_WARNING); + value.clear(); } - scope.append(1, 0x27); // terminating single quote - return std::move(scope); + return value; } // utility function to check that scope entry is valid; // valid entries can not contain '=' character or " and " string bool event_scope::check(const std::string& scope) { + if(scope.empty()) { return true; } string_list_t::const_iterator rs = RESERVED_STRINGS.cbegin(); ++rs; for(; rs != RESERVED_STRINGS.end(); ++rs) @@ -56,21 +107,10 @@ bool event_scope::check(const std::string& scope) return true; } -bool event_scope::assemble(std::string& scope, const std::string& name, const std::string& value) -{ - if(check(name) && check(value)) - { - if(scope.length()) { scope.append(" and "); } - scope.append(name).append(1, '=').append(value); - return true; - } - else - { - g_logger.log("Invalid scope entry for " + name + ": [" + value + ']', sinsp_logger::SEV_WARNING); - } - return false; -} +// +// 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): @@ -317,18 +357,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()); 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) { diff --git a/userspace/libsinsp/user_event.h b/userspace/libsinsp/user_event.h index d957b8c9c3..0a013493a8 100644 --- a/userspace/libsinsp/user_event.h +++ b/userspace/libsinsp/user_event.h @@ -28,27 +28,47 @@ along with sysdig. If not, see . // // scope utilities // -struct event_scope +class event_scope { +public: typedef std::vector string_list_t; + static const std::string SCOPE_OP_AND; static const string_list_t RESERVED_STRINGS; static const string_list_t REPLACEMENT_STRINGS; - // utility function to escape scope entries and wrap them in single quotes; - // this function is used internally but is left public for testing purposes - static string&& escape(std::string&& scope); + 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; - // valid entries can not contain '=' character or " and " string + // valid entries can not contain characters from RESERVED_STRINGS + // which are not present in REPLACEMENT_STRINGS static bool check(const std::string& scope); - // utility function to check that scope entry is valid and - // assemble it; returns true if succesful, false otherwise; - // valid entries can not contain '=' character or " and " string - static bool assemble(std::string& scope, const std::string& name, const std::string& value); +private: + + // utility function to replace RESERVED_STRINGS with their + // counterparts in REPLACEMENT_STRINGS + static string& replace(std::string& scope); + + 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 @@ -232,7 +252,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); From 59489f9f06134ce8ca6d40a44c1ca6934fc41bda Mon Sep 17 00:00:00 2001 From: Alex Fabijanic Date: Thu, 2 Feb 2017 13:21:08 -0600 Subject: [PATCH 4/7] restrict key with regex, allow anything in value (e340987) --- userspace/libsinsp/user_event.cpp | 48 +++++++++++-------------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/userspace/libsinsp/user_event.cpp b/userspace/libsinsp/user_event.cpp index 84792ebed9..acf94f4acb 100644 --- a/userspace/libsinsp/user_event.cpp +++ b/userspace/libsinsp/user_event.cpp @@ -19,6 +19,7 @@ along with sysdig. If not, see . #include "sinsp.h" #include "sinsp_int.h" #include "user_event.h" +#include // // event_scope @@ -31,9 +32,9 @@ const std::string event_scope::SCOPE_OP_AND = "and"; // 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 = - {"'"/*!must be first!*/, "=", " and ", " "}; + {"'"}; const event_scope::string_list_t event_scope::REPLACEMENT_STRINGS = - {"\\'"/*!must be first!*/}; + {"\\'"}; event_scope::event_scope(const std::string& key, const std::string& value) { @@ -60,51 +61,36 @@ bool event_scope::add(const std::string& key, const std::string& value, const st } else { - g_logger.log("Scope key has invalid value: [" + key + "], not added to scope.", sinsp_logger::SEV_WARNING); + 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()); + ASSERT(RESERVED_STRINGS.size() == REPLACEMENT_STRINGS.size()); - if(check(value)) + 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) { - trim(value); - 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) - { - replace_in_place(value, *res_it, *rep_it); - if(++rep_it == rep_end) { break; } - } - } - else - { - g_logger.log("Cannot replace invalid value: [" + value + "], string will be cleared.", sinsp_logger::SEV_WARNING); - value.clear(); + replace_in_place(value, *res_it, *rep_it); } + return value; } -// utility function to check that scope entry is valid; -// valid entries can not contain '=' character or " and " string bool event_scope::check(const std::string& scope) { - if(scope.empty()) { return true; } - string_list_t::const_iterator rs = RESERVED_STRINGS.cbegin(); - ++rs; - for(; rs != RESERVED_STRINGS.end(); ++rs) + static const std::regex r("^[a-zA-Z0-9-_/\\.]*$"); + if(std::regex_match(scope, r)) { - if(scope.find(*rs) != std::string::npos) - { - return false; - } + return true; } - return true; + return false; } From ceb8cbca94e2a5182427cc9c474630030569aea5 Mon Sep 17 00:00:00 2001 From: Alex Fabijanic Date: Fri, 3 Feb 2017 14:50:31 -0600 Subject: [PATCH 5/7] replace c++11 regex with posix --- userspace/libsinsp/user_event.cpp | 44 ++++++++++++++++++++++++++++--- userspace/libsinsp/user_event.h | 3 +++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/userspace/libsinsp/user_event.cpp b/userspace/libsinsp/user_event.cpp index acf94f4acb..cc91ab8208 100644 --- a/userspace/libsinsp/user_event.cpp +++ b/userspace/libsinsp/user_event.cpp @@ -19,7 +19,6 @@ along with sysdig. If not, see . #include "sinsp.h" #include "sinsp_int.h" #include "user_event.h" -#include // // event_scope @@ -83,13 +82,50 @@ string& event_scope::replace(std::string& value) 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) { - static const std::regex r("^[a-zA-Z0-9-_/\\.]*$"); - if(std::regex_match(scope, r)) + if(scope.empty()) { return false; } + std::string exp("[a-zA-Z0-9_/\\.]*(-[a-zA-Z0-9_/\\.]*)*"); + regex_t reg = {0}; + size_t ret = regcomp(®, exp.c_str(), REG_EXTENDED); + if(0 == ret) { - return true; + regmatch_t rm = {0}; + ret = regexec(®, scope.c_str(), 1, &rm, 0); + if(0 == ret) + { + if((rm.rm_eo - rm.rm_so) != static_cast(scope.length())) + { + regfree(®); + return false; + } + regfree(®); + return true; + } + else + { + regex_error("regexec", ret, ®, scope); + } + } + else + { + regex_error("regcomp", ret, ®, exp); } + regfree(®); return false; } diff --git a/userspace/libsinsp/user_event.h b/userspace/libsinsp/user_event.h index 0a013493a8..a7d84fd7a1 100644 --- a/userspace/libsinsp/user_event.h +++ b/userspace/libsinsp/user_event.h @@ -24,6 +24,7 @@ along with sysdig. If not, see . #include #include #include +#include // // scope utilities @@ -56,6 +57,8 @@ class event_scope // 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; }; From e909ae7f195e37fe5ff0d6a13374dfe8f3f451ea Mon Sep 17 00:00:00 2001 From: Alex Fabijanic Date: Fri, 3 Feb 2017 18:09:20 -0600 Subject: [PATCH 6/7] simplify regex check --- userspace/libsinsp/user_event.cpp | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/userspace/libsinsp/user_event.cpp b/userspace/libsinsp/user_event.cpp index cc91ab8208..8a4044185c 100644 --- a/userspace/libsinsp/user_event.cpp +++ b/userspace/libsinsp/user_event.cpp @@ -99,7 +99,8 @@ void event_scope::regex_error(const std::string& call, size_t ret, regex_t* preg bool event_scope::check(const std::string& scope) { if(scope.empty()) { return false; } - std::string exp("[a-zA-Z0-9_/\\.]*(-[a-zA-Z0-9_/\\.]*)*"); + bool result = false; + std::string exp("[a-zA-Z0-9_/\\.-]*"); regex_t reg = {0}; size_t ret = regcomp(®, exp.c_str(), REG_EXTENDED); if(0 == ret) @@ -108,25 +109,16 @@ bool event_scope::check(const std::string& scope) ret = regexec(®, scope.c_str(), 1, &rm, 0); if(0 == ret) { - if((rm.rm_eo - rm.rm_so) != static_cast(scope.length())) + if((rm.rm_eo - rm.rm_so) == static_cast(scope.length())) { - regfree(®); - return false; + result = true; } - regfree(®); - return true; - } - else - { - regex_error("regexec", ret, ®, scope); } + else { regex_error("regexec", ret, ®, scope); } } - else - { - regex_error("regcomp", ret, ®, exp); - } + else { regex_error("regcomp", ret, ®, exp); } regfree(®); - return false; + return result; } From 87e5bfdc927999f4217db18b210d18e36c158c57 Mon Sep 17 00:00:00 2001 From: Alex Fabijanic Date: Tue, 7 Feb 2017 19:41:30 -0600 Subject: [PATCH 7/7] fixes from @bertocci review --- userspace/libsinsp/user_event.cpp | 20 +++++++++++--------- userspace/libsinsp/user_event.h | 20 +++++++++++++------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/userspace/libsinsp/user_event.cpp b/userspace/libsinsp/user_event.cpp index 8a4044185c..00bb4e3f82 100644 --- a/userspace/libsinsp/user_event.cpp +++ b/userspace/libsinsp/user_event.cpp @@ -35,6 +35,9 @@ 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, ""); @@ -42,7 +45,7 @@ event_scope::event_scope(const std::string& key, const std::string& value) bool event_scope::add(const std::string& key, const std::string& value, const std::string& op) { - if(check(key)) + if(check_key_format(key)) { std::string k(key); std::string o(!m_scope.empty() ? op : ""); @@ -96,25 +99,25 @@ void event_scope::regex_error(const std::string& call, size_t ret, regex_t* preg } } -bool event_scope::check(const std::string& scope) +bool event_scope::check_key_format(const std::string& key) { - if(scope.empty()) { return false; } + if(key.empty()) { return false; } bool result = false; - std::string exp("[a-zA-Z0-9_/\\.-]*"); + std::string exp(KEY_FORMAT); regex_t reg = {0}; size_t ret = regcomp(®, exp.c_str(), REG_EXTENDED); if(0 == ret) { regmatch_t rm = {0}; - ret = regexec(®, scope.c_str(), 1, &rm, 0); + ret = regexec(®, key.c_str(), 1, &rm, 0); if(0 == ret) { - if((rm.rm_eo - rm.rm_so) == static_cast(scope.length())) + if((rm.rm_eo - rm.rm_so) == static_cast(key.length())) { result = true; } } - else { regex_error("regexec", ret, ®, scope); } + else { regex_error("regexec", ret, ®, key); } } else { regex_error("regcomp", ret, ®, exp); } regfree(®); @@ -378,12 +381,11 @@ std::string sinsp_user_event::to_string(uint64_t timestamp, const std::string from("\""); const std::string to("\\\""); - std::string s(scope.get()); 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(s, from, to) << "\"\n"; + "scope: \"" << replace_in_place(scope.get_ref(), from, to) << "\"\n"; if(sev != UNKNOWN_SEVERITY) { diff --git a/userspace/libsinsp/user_event.h b/userspace/libsinsp/user_event.h index a7d84fd7a1..369211b6f0 100644 --- a/userspace/libsinsp/user_event.h +++ b/userspace/libsinsp/user_event.h @@ -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 L nameicense +You should have received a copy of the GNU General Public License along with sysdig. If not, see . */ @@ -37,19 +37,20 @@ class event_scope 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); - std::string get(); + const std::string& get() const; + std::string& get_ref(); void clear(); - // utility function to check that scope entry is valid; - // valid entries can not contain characters from RESERVED_STRINGS - // which are not present in REPLACEMENT_STRINGS - static bool check(const std::string& scope); + // 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: @@ -62,7 +63,12 @@ class event_scope std::string m_scope; }; -inline std::string event_scope::get() +inline const std::string& event_scope::get() const +{ + return m_scope; +} + +inline std::string& event_scope::get_ref() { return m_scope; }