Skip to content

Commit

Permalink
Action semantics and related improvements (#277)
Browse files Browse the repository at this point in the history
  • Loading branch information
Anilm3 authored Mar 28, 2024
1 parent 24a89cb commit 1ba0674
Show file tree
Hide file tree
Showing 46 changed files with 2,494 additions and 329 deletions.
2 changes: 1 addition & 1 deletion .clang-tidy
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
# readability-function-cognitive-complexity temporarily disabled until clang-tidy is fixed
# right now emalloc causes it to misbehave
Checks: '*,misc-const-correctness,-bugprone-reserved-identifier,-hicpp-signed-bitwise,-llvmlibc-restrict-system-libc-headers,-altera-unroll-loops,-hicpp-named-parameter,-cert-dcl37-c,-cert-dcl51-cpp,-read,-cppcoreguidelines-init-variables,-cppcoreguidelines-avoid-non-const-global-variables,-altera-id-dependent-backward-branch,-performance-no-int-to-ptr,-altera-struct-pack-align,-google-readability-casting,-modernize-use-trailing-return-type,-llvmlibc-implementation-in-namespace,-llvmlibc-callee-namespace,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-fuchsia-default-arguments-declarations,-fuchsia-overloaded-operator,-cppcoreguidelines-pro-type-union-access,-fuchsia-default-arguments-calls,-cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes,-google-readability-todo,-llvm-header-guard,-readability-function-cognitive-complexity,-readability-identifier-length,-cppcoreguidelines-owning-memory,-cert-err58-cpp,-fuchsia-statically-constructed-objects,-google-build-using-namespace,-hicpp-avoid-goto,-cppcoreguidelines-avoid-goto,-hicpp-no-array-decay,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-abseil-string-find-str-contains,-bugprone-unchecked-optional-access'
Checks: '*,misc-const-correctness,-bugprone-reserved-identifier,-hicpp-signed-bitwise,-llvmlibc-restrict-system-libc-headers,-altera-unroll-loops,-hicpp-named-parameter,-cert-dcl37-c,-cert-dcl51-cpp,-read,-cppcoreguidelines-init-variables,-cppcoreguidelines-avoid-non-const-global-variables,-altera-id-dependent-backward-branch,-performance-no-int-to-ptr,-altera-struct-pack-align,-google-readability-casting,-modernize-use-trailing-return-type,-llvmlibc-implementation-in-namespace,-llvmlibc-callee-namespace,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-fuchsia-default-arguments-declarations,-fuchsia-overloaded-operator,-cppcoreguidelines-pro-type-union-access,-fuchsia-default-arguments-calls,-cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes,-google-readability-todo,-llvm-header-guard,-readability-function-cognitive-complexity,-readability-identifier-length,-cppcoreguidelines-owning-memory,-cert-err58-cpp,-fuchsia-statically-constructed-objects,-google-build-using-namespace,-hicpp-avoid-goto,-cppcoreguidelines-avoid-goto,-hicpp-no-array-decay,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-abseil-string-find-str-contains,-bugprone-unchecked-optional-access,-readability-use-anyofallof'
WarningsAsErrors: '*'
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
Expand Down
11 changes: 8 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,17 @@ jobs:

- name: Install dependencies
if: matrix.arch == 'arm64'
run: sudo apt update ; sudo apt install -y cmake gcc-12 g++-12 git make curl
run: sudo apt update ; sudo apt install -y cmake git make curl

- name: Install clang-{tidy,format}
run: |
sudo .github/workflows/scripts/llvm.sh 17
sudo apt-get install -y clang-17 clang++-17
- name: CMake
env:
CC: gcc-12
CXX: g++-12
CC: clang-17
CXX: clang++-17
run: |
cmake .. -DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_FLAGS="-fsanitize=address,leak,undefined -DASAN_BUILD" \
Expand Down
3 changes: 3 additions & 0 deletions cmake/objects.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ set(LIBDDWAF_SOURCE
${libddwaf_SOURCE_DIR}/src/utils.cpp
${libddwaf_SOURCE_DIR}/src/waf.cpp
${libddwaf_SOURCE_DIR}/src/platform.cpp
${libddwaf_SOURCE_DIR}/src/uuid.cpp
${libddwaf_SOURCE_DIR}/src/action_mapper.cpp
${libddwaf_SOURCE_DIR}/src/exclusion/input_filter.cpp
${libddwaf_SOURCE_DIR}/src/exclusion/object_filter.cpp
${libddwaf_SOURCE_DIR}/src/exclusion/rule_filter.cpp
${libddwaf_SOURCE_DIR}/src/generator/extract_schema.cpp
${libddwaf_SOURCE_DIR}/src/parser/actions_parser.cpp
${libddwaf_SOURCE_DIR}/src/parser/common.cpp
${libddwaf_SOURCE_DIR}/src/parser/parser.cpp
${libddwaf_SOURCE_DIR}/src/parser/parser_v1.cpp
Expand Down
85 changes: 85 additions & 0 deletions src/action_mapper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Unless explicitly stated otherwise all files in this repository are
// dual-licensed under the Apache-2.0 License or BSD-3-Clause License.
//
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2021 Datadog, Inc.

#include <stdexcept>

#include "action_mapper.hpp"
#include "uuid.hpp"

namespace ddwaf {
action_type action_type_from_string(std::string_view type)
{
if (type == "block_request") {
return action_type::block_request;
}
if (type == "redirect_request") {
return action_type::redirect_request;
}
if (type == "generate_stack") {
return action_type::generate_stack;
}
if (type == "generate_schema") {
return action_type::generate_schema;
}
if (type == "monitor") {
return action_type::monitor;
}
// Unknown actions are valid, but provide no semantic value
return action_type::unknown;
}

void action_mapper_builder::alias_default_action_to(std::string_view default_id, std::string alias)
{
auto it = default_actions_.find(default_id);
if (it == default_actions_.end()) {
throw std::runtime_error(
"attempting to add alias to non-existent default action " + std::string(default_id));
}
action_by_id_.emplace(std::move(alias), it->second);
}

void action_mapper_builder::set_action(
std::string id, std::string type, std::unordered_map<std::string, std::string> parameters)
{
if (action_by_id_.find(id) != action_by_id_.end()) {
throw std::runtime_error("duplicate action '" + id + '\'');
}

action_by_id_.emplace(std::move(id),
action_spec{action_type_from_string(type), std::move(type), std::move(parameters)});
}

[[nodiscard]] const action_spec &action_mapper_builder::get_default_action(std::string_view id)
{
auto it = default_actions_.find(id);
if (it == default_actions_.end()) {
throw std::out_of_range("unknown action " + std::string(id));
}
return it->second;
}

std::shared_ptr<action_mapper> action_mapper_builder::build_shared()
{
return std::make_shared<action_mapper>(build());
}

action_mapper action_mapper_builder::build()
{
for (const auto &[action_id, action_spec] : default_actions_) {
action_by_id_.try_emplace(action_id, action_spec);
}

return std::move(action_by_id_);
}

const std::map<std::string, action_spec, std::less<>> action_mapper_builder::default_actions_ = {
{"block", {action_type::block_request, "block_request",
{{"status_code", "403"}, {"type", "auto"}, {"grpc_status_code", "10"}}}},
{"stack_trace", {action_type::generate_stack, "generate_stack", {}}},
{"extract_schema", {action_type::generate_schema, "generate_schema", {}}},
{"monitor", {action_type::monitor, "monitor", {}}}};

} // namespace ddwaf
71 changes: 71 additions & 0 deletions src/action_mapper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Unless explicitly stated otherwise all files in this repository are
// dual-licensed under the Apache-2.0 License or BSD-3-Clause License.
//
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2021 Datadog, Inc.

#pragma once

#include <map>
#include <memory>
#include <string>
#include <string_view>
#include <unordered_map>

#include "utils.hpp"

namespace ddwaf {

enum class action_type : uint8_t {
none = 0,
unknown = 1,
generate_stack = 2,
generate_schema = 3,
monitor = 4,
block_request = 5,
redirect_request = 6, // Redirect must always be the last action
// as the value is used to serve as precedence
};

action_type action_type_from_string(std::string_view type);

inline bool is_blocking_action(action_type type)
{
return type == action_type::block_request || type == action_type::redirect_request;
}

struct action_spec {
action_type type;
std::string type_str;
std::unordered_map<std::string, std::string> parameters;
};

using action_mapper = std::map<std::string, action_spec, std::less<>>;

class action_mapper_builder {
public:
action_mapper_builder() = default;
~action_mapper_builder() = default;
action_mapper_builder(const action_mapper_builder &) = delete;
action_mapper_builder(action_mapper_builder &&) = delete;
action_mapper_builder &operator=(const action_mapper_builder &) = delete;
action_mapper_builder &operator=(action_mapper_builder &&) = delete;

void alias_default_action_to(std::string_view default_id, std::string alias);

void set_action(
std::string id, std::string type, std::unordered_map<std::string, std::string> parameters);

[[nodiscard]] static const action_spec &get_default_action(std::string_view id);

std::shared_ptr<action_mapper> build_shared();

// Used for testing
action_mapper build();

protected:
std::map<std::string, action_spec, std::less<>> action_by_id_;
static const std::map<std::string, action_spec, std::less<>> default_actions_;
};

} // namespace ddwaf
8 changes: 4 additions & 4 deletions src/collection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ std::optional<event> match_rule(rule *rule, const object_store &store,
return std::nullopt;
}

bool skip_actions = false;
action_type action_override = action_type::none;
auto exclusion = policy.find(rule);
if (exclusion.mode == exclusion::filter_mode::bypass) {
DDWAF_DEBUG("Bypassing rule '{}'", id);
Expand All @@ -38,7 +38,7 @@ std::optional<event> match_rule(rule *rule, const object_store &store,

if (exclusion.mode == exclusion::filter_mode::monitor) {
DDWAF_DEBUG("Monitoring rule '{}'", id);
skip_actions = true;
action_override = action_type::monitor;
}

DDWAF_DEBUG("Evaluating rule '{}'", id);
Expand All @@ -54,8 +54,8 @@ std::optional<event> match_rule(rule *rule, const object_store &store,
std::optional<event> event;
event = rule->match(store, rule_cache, exclusion.objects, dynamic_matchers, deadline);

if (event.has_value() && skip_actions) {
event->skip_actions = true;
if (event.has_value()) {
event->action_override = action_override;
}

return event;
Expand Down
5 changes: 1 addition & 4 deletions src/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2021 Datadog, Inc.

#include <unordered_set>

#include "context.hpp"
#include "exception.hpp"
#include "log.hpp"
#include "utils.hpp"
#include "waf.hpp"

namespace ddwaf {

Expand Down Expand Up @@ -59,7 +56,7 @@ DDWAF_RET_CODE context::run(optional_ref<ddwaf_object> persistent,
return DDWAF_OK;
}

const event_serializer serializer(*ruleset_->event_obfuscator);
const event_serializer serializer(*ruleset_->event_obfuscator, *ruleset_->actions);

optional_ref<ddwaf_object> derived;
if (res.has_value()) {
Expand Down
Loading

0 comments on commit 1ba0674

Please sign in to comment.