libddwaf-src 2.1.0

Source distribution and build integration for DataDog/libddwaf
Documentation
// 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 <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "argument_retriever.hpp"
#include "clock.hpp"
#include "condition/base.hpp"
#include "condition/shi_common.hpp"
#include "condition/shi_detector.hpp"
#include "condition/structured_condition.hpp"
#include "exclusion/common.hpp"
#include "log.hpp"
#include "object.hpp"
#include "tokenizer/shell.hpp"
#include "utils.hpp"

using namespace std::literals;

namespace ddwaf {

bool shi_detector::eval_string(const unary_argument<object_view> &resource,
    const variadic_argument<object_view> &params, condition_cache &cache,
    const object_set_ref &objects_excluded, ddwaf::timer &deadline)
{
    if (resource.value.empty()) {
        return {};
    }

    auto resource_sv = resource.value.as<std::string_view>();

    std::vector<shell_token> resource_tokens;
    for (const auto &param : params) {
        auto res = find_shi_from_params(resource_sv, resource_tokens, param.value,
            param.transformers, objects_excluded, deadline);
        if (res.has_value()) {
            auto &[highlight, param_kp] = res.value();

            DDWAF_TRACE("Target {} matched parameter value {}", param.address, highlight);

            cache.match =
                condition_match{.args = {{.name = "resource"sv,
                                             .resolved = std::string{resource_sv},
                                             .address = resource.address,
                                             .key_path = convert_key_path(resource.key_path)},
                                    {.name = "params"sv,
                                        .resolved = highlight,
                                        .address = param.address,
                                        .key_path = param_kp}},
                    .highlights = {std::move(highlight)},
                    .operator_name = "shi_detector",
                    .operator_value = {}};

            return true;
        }
    }

    return {};
}

bool shi_detector::eval_array(const unary_argument<object_view> &resource,
    const variadic_argument<object_view> &params, condition_cache &cache,
    const object_set_ref &objects_excluded, ddwaf::timer &deadline)
{
    shell_argument_array arguments{resource.value};
    if (arguments.empty()) {
        return {};
    }

    std::vector<shell_token> resource_tokens;
    for (const auto &param : params) {
        auto res = find_shi_from_params(arguments, resource_tokens, param.value, param.transformers,
            objects_excluded, deadline);
        if (res.has_value()) {
            auto &[highlight, param_kp] = res.value();

            DDWAF_TRACE("Target {} matched parameter value {}", param.address, highlight);

            cache.match =
                condition_match{.args = {{.name = "resource"sv,
                                             .resolved = std::move(arguments.resource),
                                             .address = resource.address,
                                             .key_path = convert_key_path(resource.key_path)},
                                    {.name = "params"sv,
                                        .resolved = highlight,
                                        .address = param.address,
                                        .key_path = param_kp}},
                    .highlights = {std::move(highlight)},
                    .operator_name = "shi_detector",
                    .operator_value = {}};

            return true;
        }
    }

    return {};
}

shi_detector::shi_detector(std::vector<condition_parameter> args)
    : base_impl<shi_detector>(std::move(args))
{
    shell_tokenizer::initialise_regexes();
}

// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
bool shi_detector::eval_impl(const unary_argument<object_view> &resource,
    const variadic_argument<object_view> &params, condition_cache &cache,
    const object_set_ref &objects_excluded, ddwaf::timer &deadline) const
{
    if (resource.value.is_string()) {
        return eval_string(resource, params, cache, objects_excluded, deadline);
    }

    if (resource.value.is_array()) {
        return eval_array(resource, params, cache, objects_excluded, deadline);
    }

    return {};
}
} // namespace ddwaf