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

[WIP] Object view #341

Draft
wants to merge 41 commits into
base: anilm3/v2
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
ae28858
Object abstraction through object_view
Anilm3 Sep 30, 2024
70f7191
Fix some tests
Anilm3 Oct 1, 2024
fc1de8c
Object view iterator wip
Anilm3 Oct 1, 2024
75de8cb
view-based iterator
Anilm3 Oct 1, 2024
e81ad9c
Lint
Anilm3 Oct 1, 2024
5e76425
Small fixes
Anilm3 Oct 1, 2024
7a221d6
Micro-optimizations
Anilm3 Oct 2, 2024
d250dc3
Remove unnecessary null checks
Anilm3 Oct 2, 2024
8607d93
Small changes and scalar test
Anilm3 Oct 2, 2024
84b928d
Some tests
Anilm3 Oct 2, 2024
1471442
Simplify checks
Anilm3 Oct 3, 2024
0dbf3d2
Reduce iterator stack size through object_view iterator
Anilm3 Oct 5, 2024
d661f61
Small changes
Anilm3 Oct 5, 2024
ac1c3c0
Remove checks
Anilm3 Oct 5, 2024
20e8e76
Increment/Decrement without conditionals
Anilm3 Oct 5, 2024
299a93b
Improvements?
Anilm3 Oct 6, 2024
48964ab
Minor change
Anilm3 Oct 6, 2024
a0b58c7
Add extra checks to iterator
Anilm3 Oct 6, 2024
3d34062
Add comments, small fixes
Anilm3 Oct 6, 2024
42fd17c
Improvements to maps and arrays
Anilm3 Oct 6, 2024
516e337
Minor changes
Anilm3 Oct 6, 2024
bcc822d
Minor changes
Anilm3 Oct 6, 2024
21169b9
Restrict at_unchecked types
Anilm3 Oct 6, 2024
1ef5d4a
Fix tests
Anilm3 Oct 6, 2024
1d74c0f
Add separate nullable optional_object_view and change object_view to …
Anilm3 Oct 7, 2024
1389da1
Lint fixes
Anilm3 Oct 7, 2024
c0db3cf
Remove checkes and add assertions
Anilm3 Oct 8, 2024
6374706
Add object_key to avoid string_view overheads
Anilm3 Oct 8, 2024
bb98ede
Use object_key for everything
Anilm3 Oct 8, 2024
5571647
Format
Anilm3 Oct 9, 2024
fdadce8
Fixes after rebase
Anilm3 Oct 21, 2024
6f91fb0
Merge branch 'anilm3/v2' into anilm3/object_view
Anilm3 Oct 23, 2024
6781e02
Merge branch 'anilm3/v2' into anilm3/object_view
Anilm3 Oct 24, 2024
7868aaf
Move object view test
Anilm3 Oct 24, 2024
e960e47
Format
Anilm3 Oct 24, 2024
e959091
Merge branch 'anilm3/v2' into anilm3/object_view
Anilm3 Nov 12, 2024
5dc5061
Prevent scheme matches in isolation (#360)
Anilm3 Nov 19, 2024
eb80490
Improve parsing of numbers in SQL tokenizers (#359)
Anilm3 Nov 19, 2024
79496f2
Merge branch 'master' into anilm3/object_view
Anilm3 Dec 2, 2024
b0fd0e5
Merge branch 'anilm3/v2' into anilm3/object_view
Anilm3 Dec 2, 2024
1165e50
Lint
Anilm3 Dec 2, 2024
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
11 changes: 6 additions & 5 deletions src/condition/cmdi_detector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "exclusion/common.hpp"
#include "iterator.hpp"
#include "log.hpp"
#include "object_view.hpp"
#include "platform.hpp"
#include "tokenizer/shell.hpp"
#include "transformer/common/cow_string.hpp"
Expand All @@ -40,9 +41,9 @@ namespace {
// used directly with a scalar without the need for a fully-fledged object iterator
class scalar_iterator {
public:
explicit scalar_iterator(const ddwaf_object *obj, const std::span<const std::string> & /*path*/,
explicit scalar_iterator(const ddwaf_object &obj, const std::span<const std::string> & /*path*/,
const exclusion::object_set_ref & /*exclude*/, const object_limits & /*limits*/)
: current_(obj)
: current_(&obj)
{}

~scalar_iterator() = default;
Expand All @@ -53,7 +54,7 @@ class scalar_iterator {
scalar_iterator &operator=(const scalar_iterator &) = delete;
scalar_iterator &operator=(scalar_iterator &&) noexcept = delete;

[[nodiscard]] const ddwaf_object *operator*() { return current_; }
[[nodiscard]] optional_object_view operator*() { return current_; }
bool operator++()
{
current_ = nullptr;
Expand Down Expand Up @@ -341,13 +342,13 @@ std::optional<shi_result> cmdi_impl(const ddwaf_object &exec_args,
return std::nullopt;
}

object::kv_iterator it(&params, {}, objects_excluded, limits);
kv_iterator it(params, {}, objects_excluded, limits);
for (; it; ++it) {
if (deadline.expired()) {
throw ddwaf::timeout_exception();
}

const ddwaf_object &param = *(*it);
const ddwaf_object &param = (*it).ref();
if (param.type != DDWAF_OBJ_STRING) {
continue;
}
Expand Down
4 changes: 2 additions & 2 deletions src/condition/lfi_detector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,13 @@ lfi_result lfi_impl(std::string_view path, const ddwaf_object &params,
lfi_fn = &lfi_impl_windows;
}

object::kv_iterator it(&params, {}, objects_excluded, limits);
kv_iterator it(params, {}, objects_excluded, limits);
for (; it; ++it) {
if (deadline.expired()) {
throw ddwaf::timeout_exception();
}

const ddwaf_object &param = *(*it);
const ddwaf_object &param = *((*it).ptr());
if (param.type != DDWAF_OBJ_STRING) {
continue;
}
Expand Down
8 changes: 4 additions & 4 deletions src/condition/match_iterator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@

namespace ddwaf {

template <std::size_t MinLength = 2, typename IteratorType = object::kv_iterator,
template <std::size_t MinLength = 2, typename IteratorType = kv_iterator,
typename ResourceType = std::string_view>
class match_iterator {
public:
static constexpr std::size_t npos = std::string_view::npos;

explicit match_iterator(ResourceType resource, const ddwaf_object *obj,
explicit match_iterator(ResourceType resource, const ddwaf_object &obj,
const exclusion::object_set_ref &exclude, const object_limits &limits = object_limits())
: resource_(resource), it_(obj, {}, exclude, limits)
{
for (; it_; ++it_) {
const auto *current_obj = *it_;
const auto *current_obj = (*it_).ptr();
if (current_obj->type == DDWAF_OBJ_STRING && current_obj->nbEntries >= MinLength) {
current_param_ = std::string_view{
current_obj->stringValue, static_cast<std::size_t>(current_obj->nbEntries)};
Expand Down Expand Up @@ -56,7 +56,7 @@ class match_iterator {
}

while (++it_) {
const auto *current_obj = *it_;
const auto *current_obj = (*it_).ptr();
if (current_obj->type == DDWAF_OBJ_STRING && current_obj->nbEntries >= MinLength) {
current_param_ = std::string_view{
current_obj->stringValue, static_cast<std::size_t>(current_obj->nbEntries)};
Expand Down
12 changes: 6 additions & 6 deletions src/condition/scalar_condition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ ResultType eval_object(Iterator &it, std::string_view address, bool ephemeral,
{
// The iterator is guaranteed to be valid at this point, which means the
// object pointer should not be nullptr
ddwaf_object src = *(*it);
ddwaf_object src = *((*it).ptr());

if (src.type == DDWAF_OBJ_STRING) {
if (src.stringValue == nullptr) {
Expand Down Expand Up @@ -99,7 +99,7 @@ ResultType eval_target(Iterator &it, std::string_view address, bool ephemeral,
throw ddwaf::timeout_exception();
}

if (!matcher.is_supported_type(it.type())) {
if (!matcher.is_supported_type(static_cast<DDWAF_OBJ_TYPE>(it.type()))) {
continue;
}

Expand Down Expand Up @@ -164,11 +164,11 @@ eval_result scalar_condition::eval(condition_cache &cache, const object_store &s
std::optional<condition_match> match;
// TODO: iterators could be cached to avoid reinitialisation
if (target.source == data_source::keys) {
object::key_iterator it(object, target.key_path, objects_excluded, limits_);
key_iterator it(*object, target.key_path, objects_excluded, limits_);
match = eval_target<std::optional<condition_match>>(
it, target.name, ephemeral, *matcher, target.transformers, limits_, deadline);
} else {
object::value_iterator it(object, target.key_path, objects_excluded, limits_);
value_iterator it(*object, target.key_path, objects_excluded, limits_);
match = eval_target<std::optional<condition_match>>(
it, target.name, ephemeral, *matcher, target.transformers, limits_, deadline);
}
Expand Down Expand Up @@ -212,11 +212,11 @@ eval_result scalar_negated_condition::eval(condition_cache &cache, const object_

bool match = false;
if (target_.source == data_source::keys) {
object::key_iterator it(object, target_.key_path, objects_excluded, limits_);
key_iterator it(*object, target_.key_path, objects_excluded, limits_);
match = eval_target<bool>(
it, target_.name, ephemeral, *matcher, target_.transformers, limits_, deadline);
} else {
object::value_iterator it(object, target_.key_path, objects_excluded, limits_);
value_iterator it(*object, target_.key_path, objects_excluded, limits_);
match = eval_target<bool>(
it, target_.name, ephemeral, *matcher, target_.transformers, limits_, deadline);
}
Expand Down
4 changes: 2 additions & 2 deletions src/condition/shi_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ struct shell_argument_array {
std::string resource;
};

template <typename ResourceType, typename IteratorType = object::kv_iterator>
template <typename ResourceType, typename IteratorType = kv_iterator>
std::optional<shi_result> find_shi_from_params(const ResourceType &resource,
std::vector<shell_token> &resource_tokens, const ddwaf_object &params,
const exclusion::object_set_ref &objects_excluded, const object_limits &limits,
ddwaf::timer &deadline)
{
match_iterator<2, IteratorType, ResourceType> it(resource, &params, objects_excluded, limits);
match_iterator<2, IteratorType, ResourceType> it(resource, params, objects_excluded, limits);
for (; it; ++it) {
if (deadline.expired()) {
throw ddwaf::timeout_exception();
Expand Down
3 changes: 1 addition & 2 deletions src/condition/sqli_detector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ sqli_result sqli_impl(std::string_view resource, std::vector<sql_token> &resourc
{
static constexpr std::size_t min_str_len = 3;

match_iterator<min_str_len> it(resource, &params, objects_excluded, limits);
match_iterator<min_str_len> it(resource, params, objects_excluded, limits);
for (; it; ++it) {
if (deadline.expired()) {
throw ddwaf::timeout_exception();
Expand All @@ -484,7 +484,6 @@ sqli_result sqli_impl(std::string_view resource, std::vector<sql_token> &resourc
return sqli_error::invalid_sql;
}
}

auto [param_tokens, param_tokens_begin] =
get_consecutive_tokens(resource_tokens, param_index, param_index + value.size());
if (param_tokens.empty()) {
Expand Down
2 changes: 1 addition & 1 deletion src/condition/sqli_detector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace ddwaf {

class sqli_detector : public base_impl<sqli_detector> {
public:
static constexpr unsigned version = 2;
static constexpr unsigned version = 3;
static constexpr std::array<std::string_view, 3> param_names{"resource", "params", "db_type"};

explicit sqli_detector(std::vector<condition_parameter> args, const object_limits &limits = {})
Expand Down
10 changes: 6 additions & 4 deletions src/condition/ssrf_detector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ ssrf_result ssrf_impl(const uri_decomposed &uri, const ddwaf_object &params,

std::optional<ssrf_result> parameter_injection;

match_iterator<min_str_len> it{uri.raw, &params, objects_excluded, limits};
match_iterator<min_str_len> it{uri.raw, params, objects_excluded, limits};
for (; it; ++it) {
if (deadline.expired()) {
throw ddwaf::timeout_exception();
Expand Down Expand Up @@ -215,11 +215,13 @@ ssrf_result ssrf_impl(const uri_decomposed &uri, const ddwaf_object &params,
}
}

// If the injection includes the scheme check if it's still a valid one
// If the injection includes the scheme and beyond, check if the
// potentially injected scheme is still a valid one
//
// scheme://userinfo@host:port/path?query#fragment
// ───────────────────>
if (param_index == 0 && !authorised_scheme_set.contains(uri.scheme)) {
// ───────>
if (!uri.scheme.empty() && param_index == 0 && param.size() > uri.scheme.size() &&
!authorised_scheme_set.contains(uri.scheme)) {
return {{std::string(param), it.get_current_path()}};
}

Expand Down
2 changes: 1 addition & 1 deletion src/condition/ssrf_detector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace ddwaf {

class ssrf_detector : public base_impl<ssrf_detector> {
public:
static constexpr unsigned version = 1;
static constexpr unsigned version = 2;
static constexpr std::array<std::string_view, 2> param_names{"resource", "params"};

explicit ssrf_detector(std::vector<condition_parameter> args, const object_limits &limits = {});
Expand Down
Loading